在Java使用繼承時要注意幾個小細節,不然很容易出錯。
- 建構子的呼叫順序
- compiler會自動產生無參數的建構子,會自動初始化field變數
例如:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24class Parent1{
int i;
String s;
/* compiler會自動產生無參數的建構子,
* 並且初始化field變數
* public Parent1() {
* i = 0;
* s = null;
* }
*/
}
class Parent2 extend Parent1{
public Parent2(int i){
//因為沒有指定要呼叫父類別的哪一個建構子,
//compiler會自動呼叫super()
}
}
class Son extend Parent2{
public Son(){
super(1);
}
}
new Son()的時候會呼叫Parent2的建構子(public Parent2(int i)),Parent2的建構子會呼叫Parent1的建構子(public Parent1())。
注意:當沒有寫建構子,compiler會自動產生一個無參數的建構子。在繼承過程中若沒有特別指定要呼叫父類別的哪一個建構子,compiler會自動呼叫super()。
來看一個例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32public class Base {
int i;
public Base() {
add(1);
}
public void add(int j) {
i += j;
}
}
public class Extension extends Base {
int i = 3;
public Extension() {
add(2);
}
public void add(int j) {
i += j * 2;
}
public static void main(String[] args) {
exec(new Extension());
}
private static void exec(Extension base) {
base.add(8);
System.out.println(base.i);
}
}
會印出什麼樣的結果呢?
分析:
- new Extension()的時候會呼叫Base的建構子(public Base()),呼叫add(2)。
- 因為Extension有覆寫(override)Base的add function,所以Base建構子所呼叫的add(1)是呼叫Extension中的add function。
- 因為多型的關係,當Base建構子呼叫add(1),裡面的i是Extension的i,並不是Base的i。
- 當Base建構子呼叫add(1)完畢,此時Extension的i為2。
- 接著呼叫Extension的建構子,此時會先初始化field變數,所以i會被重設為3。
- 之後是呼叫add(2),此時i為7。Extension的初始化完畢。
- 呼叫add(8)時,可以得出i = 7 +16 = 23,所以印出23。
假如將1
private static void exec(Extension base)
改成1
private static void exec(Base base)
結果還是一樣嗎?
結果是0,因為此時的i指的是Base的i。