在Java中,不要在父类的构造函数中调用会被子类重写的方法,否则运行时会遇到意想不到的错误。看一个例子就会明白:
import java.util.*; class Animal { public Animal() { eat(); } protected void eat() { System.out.println("Eat something"); } } public class Bird extends Animal { public Bird() { } @Override protected void eat() { System.out.println("Just eat worm"); } public static void main(String[]args) { new Bird(); } }输出结果如下:
显然,在执行父类的构造方法时,调用的并非是父类中的eat()方法,而是子类中重写了的eat()方法。有人也许会怀疑是在父类中没有写上this.eat(),那么如果加上this,即代码如下所示:
import java.util.*; class Animal { public Animal() { this.eat(); } protected void eat() { System.out.println("Eat something"); } } public class Bird extends Animal { public Bird() { } @Override protected void eat() { System.out.println("Just eat worm"); } public static void main(String[]args) { new Bird(); } }此时输出结果如下图所示:
显然,此时输出结果与上面的相同。那么原因是什么呢?
这其实涉及到编译时类型和运行时类型的问题,在上面的例子中,虽然使用了this,即在调用父类的构造方法中,其编译时类型确实是Animal,但是运行时类型却是Bird,因而调用的是子类中重写的eat()方法。
在上面的例子中,由于调用被子类重写的方法只是导致输出出错,严重的例子可能导致运行时错误,代码如下:
import java.util.*; class Animal { public Animal() { this.eat(); } protected void eat() { System.out.println("Eat something"); } } public class Bird extends Animal { private String wormType; public Bird() { wormType="Leafworm"; } @Override protected void eat() { System.out.println("The length of wormType is "+wormType.length()); } public static void main(String[]args) { new Bird(); } }运行结果为:
由上图可知,在编译时未出现错误,但是在运行时却出现空指针错误,原因就在于wormType还没被初始化,从而调用String.length()方法是出错。
综上可得到结论:在父类的构造方法中,如果要调用其他方法,绝对不能调用可能会被子类重写的方法,否则会出现意想不到的错误。这也就意味着,如果要父类的构造方法中要调用其他成员方法,那么要么调用private方法,要么调用final修饰的方法,因为它们都是不能被子类重写的方法。