//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
似乎调用了child中的init(),但是没有保存NAME值!为什么? 如果我将NAME移动到父级,那就没关系。然而,保留在孩子身上更合理,因为它是特定于狗的。
另外,我可以在child的构造函数中显式调用init()来解决这个问题。这不是那么好。
答案 0 :(得分:6)
执行的顺序如下:
Dog
构造函数。Animal
构造函数。Animal
构造函数调用init
方法。因为它在Dog
中被覆盖,所以会调用Dog
版本。Dog.init
中,您将name
设置为"dog"
。Dog.init
方法返回。Dog
的成员变量已初始化。这会将name
设置为null
。结果:name
将为null
。
一个很好的例子,说明为什么你不应该调用可以从构造函数中重写的方法 - 因为它会导致这样的意外。
旁注:永远不要这样做:
// Unnecessarily creating a new String object
name = new String("dog");
请改为:
name = "Dog";
永远不必从字符串文字中显式创建新的String
对象。
答案 1 :(得分: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);
}
}
这是为什么在基类构造函数中调用可覆盖的方法是非常糟糕的做法的原因之一。