關於Java建構函式(Constructor)的常見問題總結

chi633發表於2017-12-21

這篇文章總結了Java使用建構函式中最常遇到的五個問題!

1 為什麼呼叫子類的構造方法的時候,預設會呼叫父類的構造方法

看下面這個簡單的例子:

package cc;

public class Sub extends Super {
	public Sub() {
		System.out.println("Sub");
	}
	
	public static void main(String[] args) {
		Sub sub = new Sub();
	}
}

class Super {
	public Super() {
		System.out.println("Super");
	}
}
複製程式碼

Paste_Image.png

當繼承自一個類的時候,構造方法就會首先呼叫super()方法。如果沒有顯式的寫這個語句,那麼編譯器就會自動插入這個語句。這就是為什麼我們上面的那個例子程式會先呼叫super的構造方法。 但要切記,** 雖然呼叫了父類的構造方法,但只建立了一個物件也就是子物件。** 之所以要呼叫父類的構造方法,是因為super類可能需要建構函式來初始化一些私有的成員變數。 編譯器自動插入super構造方法後,子類的建構函式就會像下面這樣:

public Sub(){
    super();
    System.out.println("Sub");
}
複製程式碼

2 常見錯誤:Implicit super constructor is undefined for default constructor. Must define an explicit constructor

Implicit super constructor is undefined for default constructor. Must define an explicit constructor

這個錯誤是很多開發者經常遇到的錯誤,錯誤原因就是找不到超類中的預設建構函式。

看下面的程式碼:

package cc;

public class Sub extends Super {
	
	public Sub(String s) {
		
	}
	
	public static void main(String[] args) {
		Sub sub = new Sub();
	}
}

class Super {
	String s;
	public Super(String s) {
		this.s = s;
	}
}

複製程式碼

上面這段程式碼會報錯: Implicit super constructor Super() is undefined. Must explicitly invoke another constructor。

編譯器錯誤是因為預設的super()無參的建構函式是沒有定義的。在Java中,如果一個類沒有定義建構函式,編譯器會自動插入一個預設的無參的建構函式。 但是,如果類中定義了一個建構函式,編譯器就不會自動插入無參的建構函式了,所以如果我們不顯示定義一個無參的建構函式,那麼這個建構函式就不存在。

上一小節,我們知道,如果子類的建構函式中,沒有顯示的呼叫父類的建構函式,那麼,編譯器就會插入super(),也就是自動呼叫無參的建構函式。但是此時,父類沒有無參的建構函式,所以就會報錯了。

解決這個問題很簡單,我們可以給父類插入一個無參的建構函式,或者在子類建構函式中顯示的呼叫的父類有參建構函式。

在子類的建構函式中顯示的呼叫父類的建構函式

下面的程式碼是正確的。

Paste_Image.png

建構函式的使用規則

簡單的說,在使用的時候,子類的建構函式必須呼叫父類的建構函式,不管有沒有顯示的宣告。所以,被呼叫的父類建構函式,一定在定義好!

為什麼Java在一個類已經實現了一個帶參的建構函式的時候,不實現預設的無參建構函式?

這是個很有趣的問題。我們知道如果在一個類中沒有宣告一個建構函式,那麼編譯器會隱式的幫我們實現一個無參的建構函式,但如果我們一旦一個建構函式,不管帶不帶引數,那麼編譯器都不會提供預設的建構函式,所以這麼做的原因是為什麼呢?

有一個原因就是,如果我們給所有的類都自動實現一個無參的建構函式,就可能出現問題,會打破類的設計原則。 比如說,考慮這個Scanner類,他有幾個建構函式,你可以通過這幾個建構函式,宣告你想要讀取資料的來源,如果編譯器增加了無參的建構函式,那麼你不給定讀取的資料來源,就會報錯,程式無法執行,因為我們不能不指定一個資料來源就讓他去讀取資料。

相關文章