深入理解java抽象類
抽象類概念
在面向物件的概念中,所有的物件都是通過類來描述的,但是並不是所有的類都描述了物件,有些類裡面並沒有包含足夠的資訊來描述物件,這些類被認為是抽象類。
抽象類與普通類的區別就在於抽象類不能被例項化,這就決定了抽象類必須有子類實現它的抽象方法
定義與使用
抽象類只是在普通類的基礎上擴充了一些抽象方法而已,所謂的抽象方法指的是隻宣告而未實現的方法(即沒有方法體)。所有抽象方法要求使用abstract關鍵字來定義,並且抽象方法所在的類也一定要使用abstract關鍵字來定義,表示抽象類。
定義
下面我們寫一個抽象類看看例子:
abstract class Person{
private String name ; // 屬性
public String getName(){ // 普通方法
return this.name;
}
public void setName(String name){
this.name = name ;
}
// {}為方法體,所有抽象方法上不包含方法體
public abstract void getPersonInfo() ; //抽象方法
}
可以看到抽象類前面要加abstract修飾,抽象方法也要加abstract關鍵字
需要注意的是:一個類中如果有抽象方法,那麼這個類一定是抽象類,但是一個類如果是抽象類,它是可以沒有抽象方法的。
使用原則
- 所有的抽象類必須有子類。
- 抽象類的子類必須覆寫抽象類的所有抽象方法(子類不是抽象類)【方法覆寫一定要考慮許可權問題,權限盡量都用public】
- 抽象類的物件可以通過物件多型性利用子類為其例項化
- private與abstract不能同時使用。
下面我們寫一個使用抽象類的程式碼:
abstract class Person{
private String name ; // 屬性
public String getName(){ // 普通方法
return this.name;
}
public void setName(String name){
this.name = name ;
}
// {}為方法體,所有抽象方法上不包含方法體
public abstract void getPersonInfo() ; //抽象方法
}
class Student extends Person{
public void getPersonInfo(){//實現父類的抽象方法
System.out.println("I am a student");
}
}
public class Test{
public static void main(String[] args) {
Person per = new Student() ; //例項化子類,向上轉型
per.getPersonInfo() ; //被子類所覆寫的方法
}
}
抽象類的相關規定
在抽象類中也允許提供構造方法,並且子類也照樣遵循物件例項化流程。例項化子類時一定先呼叫父類構造方法。例如:
abstract class Person{
private String name ; // 屬性
public Person(){ //構造方法
System.out.println("**********");
}
public String getName(){ // 普通方法
return this.name;
}
public void setName(String name){
this.name = name ;
}
// {}為方法體,所有抽象方法上不包含方法體
public abstract void getPersonInfo() ; //抽象方法
}
class Student extends Person{
public Student(){ //構造方法
System.out.println("##########");
}
public void getPersonInfo(){
//空實現。
}
}
public class Test {
public static void main(String[] args) {
new Student();
}
}
結果如下:
所以說子類例項化是構造方法會先呼叫父類的構造方法。如果父類沒有無參構造,那麼子類構造必須使用super明確指出使用父類哪個構造方法。
總結
-
抽象類不能被例項化(初學者很容易犯的錯),如果被例項化,就會報錯,編譯無法通過。只有抽象類的非抽象子類可以建立物件。
-
抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
-
抽象類中的抽象方法只是宣告,不包含方法體,就是不給出方法的具體實現也就是方法的具體功能。
-
構造方法,類方法(用static修飾的方法)不能宣告為抽象方法。
-
抽象類的子類必須給出抽象類中的抽象方法的具體實現,除非該子類也是抽象類
挖坑練習
這道題我一開始也做錯了,所以在這裡整理一下:
看如下程式碼:輸出結果是什麼呢?
abstract class A{
public A(){ //3.呼叫父類構造
this.print() ; //4.呼叫被子類覆寫的方法
}
public abstract void print() ;
}
class B extends A{
private int num = 100 ;
public B(int num) { //2.呼叫子類例項化物件
super() ; //3.隱含一行語句,實際要先呼叫父類構造
this.num = num ; //7.為類中屬性初始化
}
public void print() { //5.此時子類物件的屬性還沒有被初始化
System.out.println(this.num) ; //6.對應其資料型別的預設值
}
}
public class Test{
public static void main(String[] args) {
new B(30) ; //1.例項化子類物件
new B(30).print();
}
}
這道題很容易入坑,main方法裡面例項化了一個B的物件並傳了30進去,那麼在B類中首先會呼叫構造方法,在呼叫B的構造方法時,這時候又因為B繼承於A所以又先呼叫了A的構造方法,A的構造方法裡面又呼叫了A的print方法,但是A裡面print方法時一個抽象方法,是由子類去實現的,所以這時候又來到了B類中的print方法,注意:此時num還並沒有賦值,所以輸出的應該是num型別的預設值0。
main方法中第二條語句在第一條語句的基礎上又多了一個.print(),前面的步驟和第一條語句是一樣的流程,只是後面.print()時,是指的B的print方法,而此時num是30,已經將值傳進來了,所以第二條語句輸出的結果應該是:
0
30
結果如下: