在基類的構造器中要盡量避免調用可能被繼承重寫的方法,否則在初始化時將會引發(fā)意外
一個動態(tài)綁定的方法調用會深入到繼承層次的結構中,它可以調用導出類中的方法,如果在基類的構造器中這樣做,就可能會調用某個方法,而這個方法所操縱的成員可能還未進行初始化:
class Glyph{
void draw(){
print("Glyph.draw()"); //這個方法其實并未被調用
}
Glyph{
print("Glyph() bfore draw()");
draw(); //就是在這個地方,調用了可能在導出類中重寫的方法,將可能導致意外結果
print("Glyph() after draw()");
}
}
class RoundGlyph extends Glyph{
private int radius = 1;
RoundGlyph(int r){
radius = r;
print("RoundGlyph.RounGlyph(), radius=" + radius);
}
void draw(){
print("RoundGlyph.draw(), radius = "+ radius); //基類在構造時實際調用的是此方法
}
}
public class Test(){
public static void main(String[] args){
new RoundGlyph(5); //初始化過程會先調用基類的構造器,基類初始化完成后才會進行導出類的初始化
}
}
/*
output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0 //調用了導出類中的方法,但相關參數在子類中,還未初始化
Glyph() after draw()
RoundGlyph.RounGlyph(), radius= 5 //最后才是進行導出類的初始化
*/
在使用繼承以及多態(tài)時的初始化過程:
1)在任何事件發(fā)生之前,將分配給對象的存儲空間初始化成二進制的零
2)調用基類構造器。如果此時調用了被重寫的方法,用于步驟一的緣故,方法中使用的變量值為0
3)按照聲明的順序調用成員的初始化方法
4)調用導出類的構造器主體
注: 若導出類中的方法通過“組合”方式嵌入了一個類內部的對象的引用,其值就是null
總結:
在編寫構造器時,需要盡可能用簡單的方法使對象進入正常狀態(tài),盡量避免調用其他方法。
在構造器中能夠安全調用的只有基類中的final方法(也適用于private方法,它們自動屬于final方法)。這些方法不能被覆蓋,因此才是安全的。