构造函数中的非 final 方法调用¶
ID: java/non-final-call-in-constructor
Kind: problem
Security severity:
Severity: error
Precision: very-high
Tags:
- reliability
- correctness
- logic
Query suites:
- java-security-and-quality.qls
如果构造函数调用在子类中被重写的方法,则会导致在子类初始化之前调用子类中的重写方法。这会导致意外结果。
建议¶
如果该方法可能在子类中被重写,请不要在构造函数中调用非 final 方法。
示例¶
在以下示例中,执行 new Sub("test")
会导致 NullPointerException
。这是因为子类构造函数隐式调用超类构造函数,而超类构造函数反过来又调用重写的 init
方法,在子类构造函数中初始化字段 s
之前。
public class Super {
public Super() {
init();
}
public void init() {
}
}
public class Sub extends Super {
String s;
int length;
public Sub(String s) {
this.s = s==null ? "" : s;
}
@Override
public void init() {
length = s.length();
}
}
为避免此问题
超类构造函数中的
init
方法应设为final
或private
。可以在子类构造函数本身中执行重写
init
方法中的初始化,或者委托给从子类构造函数中调用的单独的 final 或 private 方法。
参考¶
J. Bloch, *Effective Java(第二版)*,第 89-90 页。Addison-Wesley,2008 年。
Java 教程:编写 Final 类和方法。