2016-08-21 76 views
0

我正在閱讀有效的Java第2版,並且遇到了這一段。什麼時候出現以下行爲,爲什麼它會產生問題?爲什麼克隆方法不能在正在構建的克隆上調用任何非最終方法

像一個構造函數,一個克隆方法不應以正在建設中(第17項)的克隆任何非最終 方法。如果克隆調用 重寫的方法,則此方法將在 的子類之前執行,該子類定義的子類有可能修復其克隆中的狀態, 很可能導致克隆和原始文件損壞。 因此,前面的 段落中討論的put(key,value)方法應該是final或private。 (如果是私有的,它是 想必「助手方法」的非最終公共方法。)

注:我不知道,當我們覆蓋的方法()和父構造器使用方法()。當我們從子類new()中執行super()時,會調用a()而不是父類的a()。我知道同樣的問題發生在克隆()

+0

我已經添加了一個例子來說明 – Dici

回答

3

只是因爲protectedpublic non-final方法是由子類覆蓋,這是腳步到初始化問題。假設重寫方法試圖在初始化之前訪問一個字段,你會得到一個NullPointerException。假設它調用另一種方法,它依賴於在完全初始化之前不能保證的特定對象狀態,這會導致程序更加微妙的錯誤或不正確。

我要說的是已經在你的書了,所以讓我們添加一個具體的例子:

public SpaceShip { 
    private double oilLevelInLitres; 
    private String model; 

    public SpaceShip(double oilLevelInLitres, String model) { 
     this.oilLevelInLitres = oilLevelInLitres; 
     displayOilLevel(); 
     this.model = model; 
    } 

    public void displayOilLevel() { 
     System.out.println("Oil level is currently " + oilLevelInLitres + " litres"); 
    } 
} 

public SpaceShipWithSecondaryReservoir {  
    public SpaceShip(double oilLevelInLitres, double secondaryReservoirOilLevelInLitres, String oilLevelInLitres) { 
     super(oilLevelInLitres, oilLevelInLitres); 
     this.secondaryReservoirOilLevelInLitres = secondaryReservoirOilLevelInLitres; 
    } 

    public void displayOilLevel() { 
     System.out.println("Model " + model + " oil level is currently " + oilLevelInLitres + 
      " litres and " + secondaryReservoirOilLevelInLitres + " litres in the seconday reservoir"); 
    } 
} 

public Main() { 
    public static void main(String[] args) { 
     // will print "Model null oil level is currently 17.0 litres and 5.0 litres in 
     // the secondary reservoir" 
     new SpaceShipWithSecondaryReservoir(17, 5, "Falcon-3X"); 
    } 
} 

在這個例子中,你可能會說,父類也可以初始化model名調用方法前,而且你是對的,但是現在程序員編寫了父類構造函數,他假定顯示方法不需要除油位以外的任何其他狀態。

這是一個編程錯誤,通過在構造函數的末尾調用display方法可以避免,但在更復雜的情況下,它不會那麼簡單和明顯。在構造函數中調用可重寫的方法會讓您遇到一類在您只調用final或private方法時不存在的錯誤。