假设我按以下方式定义了两个类:
public class A {
public A() {
foo();
}
public void foo() {
System.out.println("A");
}
}
public class B extends A {
private String bar;
public B() {
bar = "bar";
}
@Override
public void foo() {
System.out.println(bar);
}
}
Run Code Online (Sandbox Code Playgroud)
然后我通过以下方式实例化B:
A test = new B();
Run Code Online (Sandbox Code Playgroud)
那么为什么编译器分别不能让IDE警告我在B的foo方法中会有一个NullPointer?这不是很难检查,有时非常有用.
虽然这是设计错误,但这不是语法错误.
以下是Effective Java 2nd Edition,第17项:设计和继承文档的引用,或者禁止它:
为了允许继承,类必须遵守一些限制.构造函数不得直接或间接调用可覆盖的方法.如果违反此规则,将导致程序失败.超类构造函数在子类构造函数之前运行,因此在子类构造函数运行之前将调用子类中的重写方法.如果重写方法依赖于子类构造函数执行的任何初始化,则该方法将不会按预期运行.
一个听话的编译器会让它编译得很好,因为它在语言上是合法的.幸运的是,代码分析工具可用于查找这些设计错误,例如findbugs:
UR:从超类的构造函数调用的字段方法的未初始化读取(UR_UNINIT_READ_CALLED_FROM_SUPER_CONSTRUCTOR)
在超类的构造函数中调用此方法.此时,该类的字段尚未初始化.