1. 程式人生 > >Java學習9:super(隱式引數)關鍵字記憶體分析詳解及用法

Java學習9:super(隱式引數)關鍵字記憶體分析詳解及用法

super關鍵字,是一個隱式引數(另一個隱式引數是this)。

注:super關鍵字和this關鍵字極為類似,學習時可參考this關鍵字用法。this(隱式引數)關鍵字記憶體分析詳解及用法

1.概述

super是直接父類的引用(this是當前物件的引用)。可以通過super來訪問父類中被子類覆蓋的方法或屬性。

  • super關鍵字,是一個隱式引數,另外一個隱式引數是this。
    super用於方法裡面,用於方法外面無意義。
  • super關鍵字一般用於繼承和構造方法中。
  • 任何類的建構函式中,若是建構函式的第一行程式碼沒有顯式的呼叫super(),那麼Java預設都會呼叫super();作為父類的初始化函式。所以這裡的super()加不加都無所謂 。

下面從記憶體分析的角度去理解super關鍵字,然後關注其常見用法。

2.super關鍵字記憶體分析

2.1分析程式碼

首先建立一個Bird類,及其直接父類Animal類,並分別建立其構造方法:

public class Animal {
    String name;

    public Animal() {
    }

    void eat() {
        System.out.println("have a good dinner");
    }
}

class Birds extends Animal {

    public Birds() {
    }

    @Override
    void
eat() { super.eat(); // 呼叫父類的方法 System.out.println("----------------------------------------"); // 分隔線 System.out.println("jiujiujiu"); } void fly() { System.out.println("Yeah,I can fly~~"); } }

2.2程式碼分析

在上述程式碼中,我們並沒有看到super關鍵字,事實上,在兩個構造器中,均有super(),其實該段程式碼也可以寫成:

public class Animal {
    String name;

    public Animal() {
        super(); // 呼叫父類Object構造器
    }

    void eat() {
        System.out.println("have a good dinner");
    }
}

class Birds extends Animal {

    public Birds() {
        super(); // 呼叫父類Animal構造器
    }

    @Override
    void eat() {
        super.eat(); // 呼叫父類的方法
        System.out.println("----------------------------------------"); // 分隔線
        System.out.println("jiujiujiu");
    }

    void fly() {
        System.out.println("Yeah,I can fly~~");
    }
}

可以看出,構造器中通過super()呼叫直接父類的構造器。明白了這一點,就可以進行接下來的記憶體分析。

2.3記憶體分析

接下來我們進行記憶體分析,並繪製記憶體分析圖。
首先我們建立一個測試類Test類,並聲稱一個Birds物件,如下:

class Test {
    public static void main(String[] args) {
        Birds b = new Birds();
        b.eat();
    }
}

2.3.2Test類呼叫main方法

2.3.3Birds b = new Birds();呼叫Birds構造器

這一步是最重要的,也是重點分析。
1. 當呼叫Birds類的構造器Birds()時,裡面的第一行程式碼super()(無論是否顯式寫出,都存在),回去尋找Birds類的直接父類,並且Birds構造器停留在此,不會往下執行。
2. 然後找到Animal構造器,並且同樣有super()方法,回去尋找Animal的直接父類,也就是基類Object。
3. 然後執行Object類的構造器,這裡Object時所有類的基類,他並沒有直接父類。
4. 根據Object類的程式碼資訊,生成第一個Object物件。
5. 此時Animal中的super()已經執行完成,並接著往下執行,完成了Animal構造器的全部載入,並生成一個Animal物件。
6. 同樣的,Birds中的super()也執行完成。並完成Birds構造器的全部,生成一個Birds物件。

至此,該段程式碼載入完成。如下圖:
這裡寫圖片描述

b.eat();

eat()override了父類Animal的方法,我們這裡通過b智慧呼叫Birds中的eat(),但是從圖中我們可以看到父類Animal中的eat()方法仍然存在,那我們怎麼使用呢。
答案很簡單,我們可以在Birds類中的eat()中呼叫父類的該方法,如下:

    @Override
    void eat() {
        super.eat(); // 呼叫父類的方法
        System.out.println("----------------------------------------"); // 分隔線
        System.out.println("jiujiujiu");
    }

因而,在普通方法中,可以隨意通過super呼叫父類的被override的方法。所以在方法中均存在兩個隱式引數,一個是this,一個super

3.一個有意思的小問題

之前我們提到,super()其實位於構造器的第一行,如果放在其他行會報錯,如下:

    public Birds() {
        System.out.println("sss");
        super();
    }

報錯資訊:

Constructor call must be the first statement in a constructor

構造器的呼叫必須放在構造器的首句

這句話很熟悉,我們在學習this關鍵字中也遇到過這句話,我們知道,可以通過this()呼叫過載的構造器。那麼我們可以同時使用super()和this()嗎?
首先我們知道,如果在構造器中使用this(),那麼必須具有至少兩個構造器。如下:

    public Birds() {
        super();
    }

    public Birds(String name) {
        this();
    }

我們嘗試在含參的構造器中使用super():

    public Birds(String name) {
        this();
        super();
    }

super()報錯:Constructor call must be the first statement in a constructor

換一個順序:

    public Birds(String name) {
        super();
        this();
    }

this()報錯:Constructor call must be the first statement in a constructor
無論怎樣,兩個都必須位於第一行,因而super()和this()不同出現在同一個構造器中

其實這個情況,也會出現在兩個this的情況中,一個Birds(int num,String name)想要同時呼叫兩個構造器Birds()和Birds(String name),也會出現該種情況。如下第二句是會報錯的:

    public Birds(int num, String name) {
        this();
        this("niao");
    }

Constructor call must be the first statement in a constructor
如果我們想要完成類似的呼叫,可以這麼寫:

    public Birds() {
        super();
    }

    public Birds(String name) {
        this();
    }

    public Birds(int num, String name) {
        this("niao");
    }

結論很簡單,一個構造器,只能直接呼叫一個構造器