抽象類和接口
面向對象程序設計(OOP)目前已經接近尾聲,這個小結我們再介 紹兩個重要的概念。
java中除了類,還有抽象類和接口這兩個概念,這其中有很多值得我們學習的地方,在理解和思考之前我們先用一個小結給大家看看java中怎麼定義抽象類和接口。
(1) 抽象方法和抽象類的定義
一般的方法:
public class Animal { public void eat(){
System.out.println("Animal is eating.");
}抽象方法:
public abstract class Animal { abstract void eat();
}abstract void eat(); 去掉方法體,加一個abstract 關鍵字就是一個抽象方法,如果一個類里有抽象方法,在類的聲明上必須也要加上abstract ,變成一個抽象類。我們要注意的是,抽象方法沒有方法體,所以不能直接調用,也正是因為抽象方法沒有方法體,所以我們不能直接構造一個抽象類。
其實值得我們思考的問題是,一個方法連方法體也沒有,這究竟有什麼用。答案是【約定】。
我們不能【直接構造抽象類】,但是子類可以繼承抽象類,並且必須重寫抽象方法,除非子類也是抽象類。這樣就會對所有子類有了共同約束,同時父類已經實現的方法也能被所有的子類所復用。
顧名思義:
public abstract class Animal { abstract void eat();
}這個抽象方法是為了約束子類的,讓子類必須實現這個方法。抽象類中除了擁有抽象方法,也可以擁有普通方法。
public abstract class Animal {
abstract void eat();
public void print(){
System.out.println("I'm an Animal!");
}
}抽象類無法直接進行實例化操作,當一個類實例化之後,就意味着這個對象可以調用類中的屬性或者方法了,但在抽象類里存在抽象方法,而抽象方法沒有方法體,沒有方法體就無法進行調用。既然無法進行方法調用的話,又怎麼去產生實例化對象呢。
抽象類里中也可以和其他類一樣擁有自己的成員變量:
public abstract class Animal {
private String name;
}既然有成員變量,我們大致可以猜出抽象類是可以構造的,因為屬性必須通過new去內存分配空間才能賦值啊。
那麼抽象類中一定存在構造方法,實例化的過程就是屬性賦值的過程啊!
看一下下邊的例子:
public abstract class Animal {
// 但是我們不能直接new public Animal(){
System.out.println("animal has created!");
}
abstract void eat();
public void print(){
System.out.println("I'm an Animal!");
}
}
public class Cat extends Animal {
public Cat(){
System.out.println("cat has created!");
}
@Override
void eat() {
System.out.println("cat is eating!");
}
public static void main(String[] args) {
new Cat();
}
}
結果:
animal has created!
cat has created!這個過程說明了,創建子類時,父類依然會被創建,抽象類只有在構建子類的時候才會被構建出實例。
【小問題】:抽象類可以用final聲明么?
抽象類存在的目的就是為了讓子類去繼承,一個類被final修飾了, 就失去了這個能力,結果當然是不行了。
總結一下
1. 抽象方法必須為public或者protected(因為如果為private,則不能被子類繼承,子類便無法實現該方法),缺省情況下默認為public;
2. 抽象類不能直接實例化,需要依靠子類採用向上轉型的方式處理;
3. 抽象類必須有子類,使用extends繼承,一個子類只能繼承一個抽象類;
4. 子類(如果不是抽象類)則必須覆寫抽象類之中的全部抽象方法(如果子類沒有實現父類的抽象方法,則必須將子類也定義為為abstract類。);

(2) 接口的定義
其實接口是比抽象類更高級的抽象,當然抽象類也是比類更高級的抽象。接口中只能有方法的定義,而不能有實現:
public abstract class Animal {
/**
* 呼吸的方法
*/
public abstract void breath();
/**
* 吃的方法
*/
public abstract void eat();
}我們可以更加優雅的表達出來:
public interface Animal {
/**
* 呼吸的方法
*/
void breath();
/**
* 吃的方法
*/
void eat();
}abstrac 都不需要了,但是要使用關鍵字interface ,這種類我們稱之為【接口】。
接口中能定義抽象方法,不能有實例字段、不能有方法實現(靜態的可以),java8以後在接口中可以定義默認方法,這個我們先放一放以後再講。編寫接口的目的在於對類的某些能力進行約定和規範,接口不能被實例化,沒有構造器。
接口中的方法默認是public的,我們也推薦使用默認的,也就是我們定義接口時,不用寫它的權限修飾符。但是因為接口是契約、是約定子類必須具備的某些能力,是需要子類去實現的,所以我們在寫借口時,推薦使用javadoc的方式給接口加註釋。
接口是多實現的,一個類可以實現多個接口,但是只能繼承一個類。接口之間也可以相互繼承
(1) 深入理解
我們學習了幾天的面向對象
繼承是 is-a 的關係, dog is an animal。 man is a human。
實現是 can-do的關係, 實現更體現一個類的能力,通過實現多個接口是可以聚合多個能力的。
舉一個例子:
【鳥能飛】和【飛機能飛】。它們有功能的特質嗎?其實也不太有,當時它們都能飛。
我們在設計上就可以定一個接口,接口有fly的方法定義。
接口是可以多實現的,所以鳥和飛機除了實現飛行的接口還能實現很多其他的接口。這也就意味着它們can-do 很多事情。
抽象類是模板式的設計,而接口是契約式設計。
抽象類設計時往往就是將相同實現方法抽象在父類,由子類獨立實現那些實現各自不同的實現。
【做好頂層設計】
中央政府我我們規劃藍圖,做好頂層設計,具體的實現具體來,只要跟着黨的路線走就好了。
我們再舉一個例子,比如食物鏈,動物會吃其他動物,也會被其他動物吃
//動物
public interface Animal {
/**
* 吃的方法
*/
void eat(Animal animal);
/**
* 獲取名字
* @return
*/
String getName();
}
//老虎
public class Tiger implements Animal {
@Override
public void eat(Animal animal) {
System.out.println(this.getName() + "吃了" + animal.getName());
}
@Override
public String getName() {
return "tiger";
}
}
//狼
public class Wolf implements Animal { @Override
public void eat(Animal animal) {
System.out.println(this.getName() + "吃了" + animal.getName());
}
@Override
public String getName() {
return "wolf";
}
}
//羊
public class Sheep implements Animal { @Override
public void eat(Animal animal) {
System.out.println(this.getName() + "吃了" + animal.getName());
@Override
public String getName() {
return "sheep";
}
public static void main(String[] args) {
Animal tiger = new Tiger();
Animal wolf = new Wolf();
Animal sheep = new Sheep();
wolf.eat(sheep); tiger.eat(wolf);
}
}
結果:
//wolf吃了sheep
//tiger吃了wolf公司裡邊,牛逼的人寫接口。接口更多的是設計的工作,實現更多是搬磚的工作。
原創文章,作者:投稿專員,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/250089.html
微信掃一掃
支付寶掃一掃