構建器調用的分級結構(順序)為我們帶來了一個有趣的問題
或者說讓我們進入了一種進退兩難的局面
若當前位於一個構建器的內部
同時調用准備構建的那個對象的一個動態綁定方法
那麼會出現什麼情況呢?在原始的方法內部
我們完全可以想象會發生什麼——動態綁定的調用會在運行期間進行解析
因為對象不知道它到底從屬於方法所在的那個類
還是從屬於從它衍生出來的某些類
為保持一致性
大家也許會認為這應該在構建器內部發生
但實際情況並非完全如此
若調用構建器內部一個動態綁定的方法
會使用那個方法被覆蓋的定義
然而
產生的效果可能並不如我們所願
而且可能造成一些難於發現的程序錯誤
從概念上講
構建器的職責是讓對象實際進入存在狀態
在任何構建器內部
整個對象可能只是得到部分組織——我們只知道基礎類對象已得到初始化
但卻不知道哪些類已經繼承
然而
一個動態綁定的方法調用卻會在分級結構裡
向前
或者
向外
前進
它調用位於衍生類裡的一個方法
如果在構建器內部做這件事情
那麼對於調用的方法
它要操縱的成員可能尚未得到正確的初始化——這顯然不是我們所希望的
通過觀察下面這個例子
這個問題便會昭然若揭
//: PolyConstructors
java
// Constructors and polymorphism
// don
t produce what you might expect
abstract class Glyph {
abstract void draw();
Glyph() {
System
out
println(
Glyph() before draw()
);
draw();
System
out
println(
Glyph() after draw()
);
}
}
class RoundGlyph extends Glyph {
int radius =
;
RoundGlyph(int r) {
radius = r;
System
out
println(
RoundGlyph
RoundGlyph()
radius =
+ radius);
}
void draw() {
System
out
println(
RoundGlyph
draw()
radius =
+ radius);
}
}
public class PolyConstructors {
public static void main(String[] args) {
new RoundGlyph(
);
}
} ///:~
在Glyph中
draw()方法是
抽象的
(abstract)
所以它可以被其他方法覆蓋
事實上
我們在RoundGlyph中不得不對其進行覆蓋
但Glyph構建器會調用這個方法
而且調用會在RoundGlyph
draw()中止
這看起來似乎是有意的
但請看看輸出結果
Glyph() before draw()
RoundGlyph
draw()
radius =
Glyph() after draw()
RoundGlyph
RoundGlyph()
radius =
當Glyph的構建器調用draw()時
radius的值甚至不是默認的初始值
而是
這可能是由於一個點號或者屏幕上根本什麼都沒有畫而造成的
這樣就不得不開始查找程序中的錯誤
試著找出程序不能工作的原因
前一節講述的初始化順序並不十分完整
而那是解決問題的關鍵所在
初始化的實際過程是這樣的
(
) 在采取其他任何操作之前
為對象分配的存儲空間初始化成二進制零
(
) 就象前面敘述的那樣
調用基礎類構建器
此時
被覆蓋的draw()方法會得到調用(的確是在RoundGlyph構建器調用之前)
此時會發現radius的值為
這是由於步驟(
)造成的
(
) 按照原先聲明的順序調用成員初始化代碼
(
) 調用衍生類構建器的主體
采取這些操作要求有一個前提
那就是所有東西都至少要初始化成零(或者某些特殊數據類型與
零
等價的值)
而不是僅僅留作垃圾
其中包括通過
合成
技術嵌入一個類內部的對象句柄
如果假若忘記初始化那個句柄
就會在運行期間出現違例事件
其他所有東西都會變成零
這在觀看結果時通常是一個嚴重的警告信號
在另一方面
應對這個程序的結果提高警惕
從邏輯的角度說
我們似乎已進行了無懈可擊的設計
所以它的錯誤行為令人非常不可思議
而且沒有從編譯器那裡收到任何報錯信息(C++在這種情況下會表現出更合理的行為)
象這樣的錯誤會很輕易地被人忽略
而且要花很長的時間才能找出
因此
設計構建器時一個特別有效的規則是
用盡可能簡單的方法使對象進入就緒狀態
如果可能
避免調用任何方法
在構建器內唯一能夠安全調用的是在基礎類中具有final屬性的那些方法(也適用於private方法
它們自動具有final屬性)
這些方法不能被覆蓋
所以不會出現上述潛在的問題
From:http://tw.wingwit.com/Article/program/Java/JSP/201311/19731.html