1. 程式人生 > >深入理解java抽象類

深入理解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

結果如下:
在這裡插入圖片描述