Java 抽象類 在上文我們的多態的講解中,我們父類設定了一些方法,設定的主要目的是讓子類繼承父類去覆寫那些方法,來展示不同的結果。換句話說,我們不關心父類方法里的具體實現,反正會被子類的方法覆寫,那麼我們就可以讓父類更抽象一下,抽象到只有方法的聲明,而沒有方法體。我們管這種方法叫做抽象方法,管包含 ...
Java 抽象類
在上文我們的多態的講解中,我們父類設定了一些方法,設定的主要目的是讓子類繼承父類去覆寫那些方法,來展示不同的結果。換句話說,我們不關心父類方法里的具體實現,反正會被子類的方法覆寫,那麼我們就可以讓父類更抽象一下,抽象到只有方法的聲明,而沒有方法體。我們管這種方法叫做抽象方法,管包含抽象方法的類叫做抽象類。
抽象類的特點
抽象類里只要含有一個或者一個以上的抽象方法就是抽象類,但如果一個抽象方法都沒有,那這個抽象類也沒有建立的意義。抽象方法是具有如下格式的方法
[public] abstract 返回類型 方法名(參數列表);
抽象方法是沒有方法體的 ,所以方法名寫完就會加;
表示方法聲明結束,抽象法方法體用abstract
修飾,表示這是一個抽象的方法,訪問修飾符只能用public或者是protected,或者是預設訪問許可權,就是不能用private,因為根本無法去繼承
同樣,抽象類的格式如下:
[public] abstract class 類名{
[public] abstract 返回類型 方法名(參數列表);
}
抽象類的是前面加abstract
修飾,表示這個是一個抽象類,訪問修飾符只能用public或者是protected,或者是預設訪問許可權,不能用private的原因和上面一樣。
抽象類創造的意義是將方法的聲明與方法的實現分隔開,從而實現多態。那麼他就具有如下的特點:
- 抽象類不能被實例化,也就是說不能直接創建一個抽象類的對象,但抽象類是可以有構造函數的,如果是有參構造函數,則子類要去顯示調用它。
- 抽象類是用來被繼承的,方法是要被覆寫的,如果子類繼承了抽象的父類,則需要覆寫父類的抽象方法,如果沒有覆寫,則子類必須也要定義為抽象類。
abstract是不能與private static,final 修飾符一起使用來修飾方法。
這裡我們解釋一下第三點,abstract不能與private一起用,因為private修飾的方法和類,都是無法再類之外被訪問到。也就沒有繼承的可能性。abstract不能和static一起用,是因為abstract的作用是實現多態,而實現多態則依賴於繼承和覆寫。static修飾的方法雖能被子類所繼承,但是我們修改了繼承後的方法時,這個就不能算作是覆寫,而是父類的方法被隱藏掉了,只有通過
父類名.方法名
的形式顯示調用它,這個實現不了多態。從另一個角度來看,靜態的方法是編譯的時候就確定了,無法實現後期綁定,也就不存在運行時在決定方法調用的可能。所以static修飾的方法是可以被繼承,但無法實現多態,自然也就不能和abstract
一起使用。
abstract不能和final一起使用的原因和上面一樣,final修飾的方法無法被繼承,自然也談不上多態,所以abstract無法和final一起用。
抽象類舉例
我們把上文多態的例子,繼續修改,抽象化。我們把Animal的代碼改成如下樣子。
public abstract class Animal {
abstract void run();
}
我們Dog,Cat類的代碼不需要改變。
public class Dog extends Animal{
@Override
public void run() {
System.out.println("狗在奔跑");
}
}
public class Cat extends Animal{
@Override
public void run() {
System.out.println("貓在奔跑");
}
}
其他Print類,和Test類的代碼也保持不變,代碼如下:
public class Print {
public void print(Animal animal) {
animal.run();
}
}
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
new Print().print(dog);
new Print().print(cat);
}
}
我們可以看出抽象類和之前普通類,在其他地方的改動基本是沒有的,只是將方法變得抽象,意義上更加明確。
抽象總結
創建抽象類和抽象方法是很有意義的,他能讓我們設計類的時候使類的含義更加明確,通過抽象的思想,讓類變得更加通用,聲明一系列的方法來告訴用戶打算怎麼去使用它。
Java 介面
介面可以看出一種協議,一種要求,我們繼承他來知道我們可以做什麼,具體怎麼做則取決與我們。比如KFC就是一個介面,我們一看他就知道裡面有買漢堡,炸雞,可樂,但是具體的味道和服務又會根據不同的店,有不同的樣子,這就是介面的意義。所以我們這裡也可以看出介面里的方法也應該是抽象的。
介面的特點
Java中介面的寫法如下:
[public] interface InterfaceName {
成員變數
方法聲明
}
介面區別於類,他不是用class來修飾,他用特定的interface
關鍵字,訪問修飾符與class一致,可以用public或者預設。裡面只有抽象方法和成員變數兩種內容。成員變數會預設添加public static final
意為成員變數歸類所有,訪問許可權是最大的,但是不能別繼承和修改。這也看出介面是因為不能被實例化,才會這樣約定的,介面的成員變數不允許為空,在定義的時候就要賦值給他。 而介面的方法則預設為抽象方法,預設添加public abstract
和抽象方法一樣,只能寫方法聲明。
不同於我們用extends
去繼承一個類,我們用implements
來表示實現這個介面。
class ClassName implements Interface1{
}
介面作為一個特殊的存在,是有一些他的獨特的地方的。
- 一個類是可以實現多個介面的,這在一定程度上實現了Java的多繼承。
- 介面是不能被實例化,不同於抽象類,介面的內部只能由成員變數和抽象方法,是不可以存在靜態變數塊,以及構造器的。
- 我們是可以聲明一個介面類型的變數,但是只能引用一個實現了這個介面的類。
- 同抽象方法,實現了介面的類必須實現介面的所有方法,否則就會變成抽象類。
介面舉例
看過抽象的例子,我們可能想,我們把Animal從抽象換成介面,不就實現了一個介面的例子嘛,其他地方基本也不用去改動。但這顯然是錯的。我們並不能去說Animal是一個介面,我們上面說了,介面是一種協議,規定我們能做什麼,而不是一個事物的抽象。從這裡我們也能看出介面和抽象的不同,抽象更多的是一種重構而產生的東西,我們先有dog,cat類,然後才會把他們共性的東西提取出來,放到一個更通用,更抽象的父類Animal中,而我們發現Animal不需要管run方法是怎麼實現的,所以我們將run方法設定為抽象的方法,從而將Animal類設為抽象類,等待去=繼承者來實現run。這是一種從下而上的設計思想。但是介面不是,介面一開始就是設定好的,我們根據設定好的介面從上往下去寫。介面先規定好了有什麼方法,然後我們再去具體實現他。這是一種從上而下的設計思想。
所以,我們不能將Animal設為介面,但是我們可以將Print設為介面,他規定我們有一個print()方法,代碼如下:
public interface Print {
void print(Object obj);
}
那我們就可以寫一個新的類去實現這個Print介面。代碼如下:
public class SimplePrint implements Print{
@Override
public void print(Object obj) {
((Animal)obj).run();
}
}
除了Test類以外,其他地方都不需要改變。我們Test類代碼如下:
public class Test {
public static void main(String[] args) {
Animal dog = new Dog();
Animal cat = new Cat();
Print print = new SimplePrint();
print.print(dog);
print.print(cat);
}
}
介面總結
介面和抽象雖然都是通過抽象的方法來提供我們實現多態的方式,但是他們卻是兩個不同的設計思想。這裡關於介面的講解比較簡單,關於介面自身的繼承,介面內部包含其他介面,以及利用介面來實現回調等等留在以後的文章專門來說。這裡主要是通過對比來瞭解抽象和介面。