在基類的構(gòu)造器中要盡量避免調(diào)用可能被繼承重寫的方法,否則在初始化時(shí)將會(huì)引發(fā)意外
一個(gè)動(dòng)態(tài)綁定的方法調(diào)用會(huì)深入到繼承層次的結(jié)構(gòu)中,它可以調(diào)用導(dǎo)出類中的方法找颓,如果在基類的構(gòu)造器中這樣做台腥,就可能會(huì)調(diào)用某個(gè)方法,而這個(gè)方法所操縱的成員可能還未進(jìn)行初始化:
class Glyph{
void draw(){
print("Glyph.draw()"); //這個(gè)方法其實(shí)并未被調(diào)用
}
Glyph{
print("Glyph() bfore draw()");
draw(); //就是在這個(gè)地方败去,調(diào)用了可能在導(dǎo)出類中重寫的方法,將可能導(dǎo)致意外結(jié)果
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); //基類在構(gòu)造時(shí)實(shí)際調(diào)用的是此方法
}
}
public class Test(){
public static void main(String[] args){
new RoundGlyph(5); //初始化過程會(huì)先調(diào)用基類的構(gòu)造器烈拒,基類初始化完成后才會(huì)進(jìn)行導(dǎo)出類的初始化
}
}
/*
output:
Glyph() before draw()
RoundGlyph.draw(), radius = 0 //調(diào)用了導(dǎo)出類中的方法圆裕,但相關(guān)參數(shù)在子類中,還未初始化
Glyph() after draw()
RoundGlyph.RounGlyph(), radius= 5 //最后才是進(jìn)行導(dǎo)出類的初始化
*/
在使用繼承以及多態(tài)時(shí)的初始化過程:
1)在任何事件發(fā)生之前荆几,將分配給對(duì)象的存儲(chǔ)空間初始化成二進(jìn)制的零
2)調(diào)用基類構(gòu)造器吓妆。如果此時(shí)調(diào)用了被重寫的方法,用于步驟一的緣故吨铸,方法中使用的變量值為0
3)按照聲明的順序調(diào)用成員的初始化方法
4)調(diào)用導(dǎo)出類的構(gòu)造器主體
注: 若導(dǎo)出類中的方法通過“組合”方式嵌入了一個(gè)類內(nèi)部的對(duì)象的引用行拢,其值就是null
總結(jié):
在編寫構(gòu)造器時(shí),需要盡可能用簡單的方法使對(duì)象進(jìn)入正常狀態(tài)诞吱,盡量避免調(diào)用其他方法舟奠。
在構(gòu)造器中能夠安全調(diào)用的只有基類中的final方法(也適用于private方法,它們自動(dòng)屬于final方法)房维。這些方法不能被覆蓋沼瘫,因此才是安全的。