Java 抽象類
本小節我們將學習 Java 中的抽象類,你將了解到抽象類的概念和特點,抽象類在程序設計時的應用場景,什么是抽象方法,抽象方法有什么特點,如何聲明一個抽象方法等內容。
1. 概念和特點
在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,并不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。
值得注意的是,一個抽象類不能直接實例化,但類的其他功能依然存在;既然不能被實例化,那么它必須被繼承才能被使用。
2. 為什么需要抽象類
當某個父類只知道其子類應該包含什么方法,但不知道子類如何實現這些方法的時候,抽象類就派上用場了。使用抽象類還有一個好處,類的使用者在創建對象時,就知道他必須要使用某個具體子類,而不會誤用抽象的父類,因此對于使用者來說,有一個提示作用。
例如,父類 Pet
被子類 Cat
和 Dog
繼承,并且都重寫了父類的 eat
方法:
class Pet {
// 定義方法 eat
public void eat() {
System.out.println("寵物都會吃東西");
}
}
class Dog extends Pet { // 繼承父類
// 重寫父類方法 eat
@Override
public void eat() {
System.out.println("狗狗吃狗糧");
}
}
class Cat extends Pet { // 繼承父類
// 重寫父類方法 eat
@Override
public void eat() {
System.out.println("貓貓吃貓糧");
}
}
小貓類、小狗類這些子類都重寫了寵物類中的 eat
方法,我們知道每種寵物都有吃的行為,寵物表示了一個抽象的概念。那么寵物類的實例化和方法調用就沒有了實際意義:
Pet pet = new Pet();
pet.eat();
我們知道了抽象類不能被實例化,此時可以將父類設定為抽象類,使用 abstract
關鍵字來聲明抽象類,abstract
關鍵字必須放在 class
關鍵字前面 :
// 聲明抽象類
abstract class Pet {
...
}
如果你嘗試實例化抽象類 Pet
,編譯器將會報錯:
Pet.java:4: 錯誤: Pet是抽象的; 無法實例化
new Pet();
^
1 個錯誤
使用抽象類,我們既可以通過父類和子類的繼承關系,來限制子類的設計隨意性,也可以避免父類的無意義實例化。
3. 抽象方法
抽象類中可以包含抽象方法,它是沒有具體實現的方法。換句話說,與普通方法不同的是,抽象方法沒有用 {}
包含的方法體。
抽象類可以定義一個完整的編程接口,從而為子類提供實現該編程接口所需的所有方法的方法聲明。抽象類可以只聲明方法,而不關心這些方法的具體實現,而子類必須去實現這些方法。
上面我們將 Pet
父類改為了抽象類,其中包含了 eat
方法的具體實現,而實際上這個方法是不需要具體實現的,每種寵物都有各自的具體實現。此時,就可以將 eat
方法改為抽象方法:
abstract class Pet {
abstract void eat();
}
我們可以看到抽象方法使用 abstract
關鍵字聲明,它沒有方法體,而直接使用 ;
結尾。
子類必須實現父類中的抽象方法,假如 Dog
類繼承了抽象類 Pet
,但沒有實現其抽象方法 eat
:
class Dog extends Pet {
}
編譯執行代碼,將會報錯:
Dog.java:1: 錯誤: Dog不是抽象的, 并且未覆蓋Pet中的抽象方法eat()
public class Dog extends Pet {
^
1 個錯誤
上述報錯中可知,如果我們不想在 Dog
中重寫抽象方法 eat()
,那么可以將 Dog
也改為抽象類:
abstract class Dog extends Pet {
}
抽象方法不能是 final
、static
和 native
的;并且抽象方法不能是私有的,即不能用 private
修飾。因為抽象方法一定要被子類重寫,私有方法、最終方法以及靜態方法都不可以被重寫,因此抽象方法不能使用 private
、final
以及 static
關鍵字修飾。而 native
是本地方法,它與抽象方法不同的是,它把具體的實現移交給了本地系統的函數庫,沒有把實現交給子類,因此和 abstract
方法本身就是沖突的。
4. 小結
可以使用 abstract
關鍵字聲明抽象類或抽象方法。
抽象類不能被實例化,抽象類中的方法必須被非抽象子類實現,它必須被繼承才能被使用。
抽象類中不一定包含抽象方法,但抽象方法一定在抽象類中。