2012-02-22 43 views
1
//src/com/test/animal/Animal.java 
package com.test.animal; 

public class Animal 
{ 
    Animal() 
    { 
     init(); 
    } 

    public void init() 
    { 
     System.out.println("parent init()"); 
    } 
} 

//src/com/test/animal/Dog.java 
package com.test.animal; 

public class Dog extends Animal 
{ 
    String name = null; 

    Dog() 
    { 
     super(); 
    } 

    public void init() 
    { 
     System.out.println("child init()"); 
     super.init(); 
     name = new String("dog"); 
     System.out.println("name: "+name); 
    } 

    public static void main(String[] args) 
    { 
     Dog d = new Dog(); 
     System.out.println("name: "+d.name); 
    } 
} 

輸出是:成員在子類中沒有初始化

child init() 
parent init() 
name: dog 
name: null 

似乎在init()兒童被調用,但不保存NAME值!爲什麼? 如果我將NAME移動到父項,那就沒問題了。但是,保留在孩子身上更合理,因爲它是狗特有的。

此外,我可以顯式調用子的構造函數中的init()來解決這個問題。這不太好。

+0

它不回答你的問題,但它是相關的: http://stackoverflow.com/questions/94361/when-do-you-use-javas-override-annotation-and-why – unludo 2012-02-22 08:24:37

回答

6

在此執行的順序如下:

  1. Dog構造函數被調用。
  2. 它調用Animal構造函數。
  3. 構造函數Animal調用init方法。因爲它在Dog中被覆蓋,所以調用Dog版本。
  4. Dog.init中,您將name設置爲"dog"
  5. Dog.init方法返回。
  6. 現在,Dog的成員變量被初始化。這將name設置爲null

結果:name將是null

一個很好的例子,爲什麼你不應該調用可以從構造函數重寫的方法 - 因爲它會導致像這樣的驚喜。

邊注:永遠不要這樣做:

// Unnecessarily creating a new String object 
name = new String("dog"); 

只是這樣做,而不是:

name = "Dog"; 

這是從來沒有必要明確地創建一個字符串字面量新String對象。

+0

謝謝!我曾經閱讀過關於'new String()'的東西,看起來像有效的java。感謝您的提醒。 – pengguang001 2012-02-22 08:41:45

1

這是因爲Animal的構造函數首先被調用,其中name被設置爲「dog」,然後調用Dog的構造函數,其中name被重置爲null。

使其更清晰,你的代碼是類似以下內容:

public class Dog extends Animal 
{ 
    String name; 

    Dog() 
    { 
     super(); 
     name = null; 
    } 

    public void init() 
    { 
     System.out.println("child init()"); 
     super.init(); 
     name = new String("dog"); 
     System.out.println("name: "+name); 
    } 

    public static void main(String[] args) 
    { 
     Dog d = new Dog(); 
     System.out.println("name: "+d.name); 
    } 
} 

這就是爲什麼調用基類的構造函數的可重寫方法的原因之一,是非常不好的做法。

+0

謝謝。我對孩子的構造函數中的'name = null'感到驚訝!有沒有關於此的任何鏈接或文檔? – pengguang001 2012-02-22 08:39:55

+0

其實很簡單。在構造函數之外完成的所有初始化實際上是在調用超類構造函數之後,在實際構造函數的代碼之前完成的。 – 2012-02-22 08:51:30