本文已收錄《Java常見面試題》:https://gitee.com/mydb/interview
this 和 super 都是 Java 中常見的關鍵字,雖然二者在很多情況下都可以被省略,但它們在 Java 中所起的作用是不可磨滅的。它們都是用來起指代作用的,每個類在例項化的時候之所以能呼叫到 Object 類(Object 類是所有類的父類),全是二者的“功勞”。
1.super 關鍵字
super 是用來訪問父類例項屬性和方法的。
1.1 super 方法使用
每個例項類如果沒有顯示的指定構造方法,那麼它會生成一個隱藏的無參構造方法。對於 super() 方法也是類似,如果沒有顯示指定 super() 方法,那麼子類會生成一個隱藏的 super() 方法,用來呼叫父類的無參構造方法,這就是咱們開篇所說的“每個類在例項化的時候之所以能呼叫到 Object 類,就是預設 super 方法起作用了”,接下來我們透過例項來驗證一下這個說法。
PS:所謂的“顯示”,是指在程式中主動的呼叫,也就是在程式中新增相應的執行程式碼。
public class SuperExample {
// 測試方法
public static void main(String[] args) {
Son son = new Son();
}
}
/**
* 父類
*/
class Father {
public Father() {
System.out.println("執行父類的構造方法");
}
}
/**
* 子類
*/
class Son extends Father {
}
在以上程式碼中,子類 Son 並沒有顯示指定 super() 方法,我們執行以上程式,執行的結果如下:
從上述的列印結果可以看出,子類 Son 在沒有顯示指定 super() 方法的情況下,竟然呼叫了父類的無參構造方法,這樣從側面驗證了,如果子類沒有顯示指定 super() 方法,那麼它也會生成一個隱藏的 super() 方法。這一點我們也可以從此類生成的位元組碼檔案中得到證實,如下圖所示:
super 方法注意事項
如果顯示使用 super() 方法,那麼 super() 方法必須放在構造方法的首行,否則編譯器會報錯,如下程式碼所示:
如上圖看到的那樣,如果 super() 方法沒有放在首行,那麼編譯器就會報錯:提示 super() 方法必須放到構造方法的首行。
為什麼要把 super() 方法放在首行呢?
這是因為,只要將 super() 方法放在首行,那麼在例項化子類時才能確保父類已經被先初始化了。
1.2 super 屬性使用
使用 super 還可以呼叫父類的屬性,比如以下程式碼可以透過子類 Son 呼叫父類中的 age 屬性,實現程式碼如下:
public class SuperExample {
// 測試方法
public static void main(String[] args) {
Son son = new Son();
}
}
/**
* 父類
*/
class Father {
// 定義一個 age 屬性
public int age = 30;
public Father() {
super();
System.out.println("執行父類的構造方法");
}
}
/**
* 子類
*/
class Son extends Father {
public Son() {
System.out.println("父類 age:" + super.age);
}
}
以上程式的執行結果如下圖所示,在子類中成功地獲取到了父類中的 age 屬性:
2.this 關鍵字
this 是用來訪問本類例項屬性和方法的,它會先從本類中找,如果本類中找不到則在父類中找。
2.1 this 屬性使用
this 最常見的用法是用來賦值本類屬性的,比如常見的 setter 方法,如下程式碼所示:
上述程式碼中 this.name 表示 Person 類的 name 屬性,此處的 this 關鍵字不能省略,如果省略就相當於給當前的區域性變數 name 賦值 name,自己給自己賦值了。我們可以嘗試一下,將 this 關鍵字取消掉,實現程式碼如下:
class Person {
private String name;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
public class ThisExample {
public static void main(String[] args) {
Person p = new Person();
p.setName("磊哥");
System.out.println(p.getName());
}
}
以上程式的執行結果如下圖所示:
從上述結果可以看出,將 this 關鍵字去掉之後,賦值失敗,Person 物件中的 name 屬性就為 null 了。
2.2 this 方法使用
我們可以使用 this() 方法來呼叫本類中的構造方法,具體實現程式碼如下:
public class ThisExample {
// 測試方法
public static void main(String[] args) {
Son p = new Son("Java");
}
}
/**
* 父類
*/
class Father {
public Father() {
System.out.println("執行父類的構造方法");
}
}
/**
* 子類
*/
class Son extends Father {
public Son() {
System.out.println("子類中的無參構造方法");
}
public Son(String name) {
// 使用 this 呼叫本類中無參的構造方法
this();
System.out.println("子類有參構造方法,name:" + name);
}
}
以上程式的執行結果如下圖所示:
從上述結果中可以看出,透過 this() 方法成功呼叫到了本類中的無參構造方法。
注意:this() 方法和 super() 方法的使用規則一樣,如果顯示的呼叫,只能放在方法的首行。
2.3 this 訪問父類方法
接下來,我們嘗試使用 this 訪問父類方法,具體實現程式碼如下:
public class ThisExample {
public static void main(String[] args) {
Son son = new Son();
son.sm();
}
}
/**
* 父類
*/
class Father {
public void fm() {
System.out.println("呼叫了父類中的 fm() 方法");
}
}
/**
* 子類
*/
class Son extends Father {
public void sm() {
System.out.println("呼叫子類的 sm() 方法訪問父類方法");
// 呼叫父類中的方法
this.fm();
}
}
以上程式的執行結果如下:
從上述結果可以看出,使用 this 是可以訪問到父類中的方法的,this 會先從本類中找,如果找不到則會去父類中找。
3.this 和 super 的區別
① 指代的物件不同
super 指代的是父類,是用來訪問父類的;而 this 指代的是當前類。
② 查詢範圍不同
super 只能查詢父類,而 this 會先從本類中找,如果找不到則會去父類中找。
③ 本類屬性賦值不同
this 可以用來為本類的例項屬性賦值,而 super 則不能實現此功能。
④ this 可用於 synchronized
因為 this 表示當前物件,所以this 可用於 synchronized(this){....} 加鎖,而 super 則不能實現此功能。
總結
this 和 super 都是 Java 中的關鍵字,都起指代作用,當顯示使用它們時,都需要將它們放在方法的首行(否則編譯器會報錯)。this 表示當前物件,super 用來指代父類物件,它們有四點不同:指代物件、查詢訪問、本類屬性賦值和 synchronized 的使用不同。
是非審之於己,譭譽聽之於人,得失安之於數。
公眾號:Java面試真題解析