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");
}
結論很簡單,一個構造器,只能直接呼叫一個構造器。