コンストラクタの実装から、そのクラスのオーバライド可能なメソッドを呼び出すと、サブクラス化によって動作を破壊されることがあります。
このような呼び出しは、静的解析ツールの PMD で ConstructorCallsOverridableMethod
警告として検出されます。
例えば、下記は PMD のサイトに掲載されている(正しく動作しない)サンプルコードです。
public class SeniorClass {
public SeniorClass(){
toString(); // may throw NullPointerException if overridden
}
public String toString(){
return "IAmSeniorClass";
}
}
public class JuniorClass extends SeniorClass {
private String name;
public JuniorClass(){
super(); // Automatic call leads to NullPointerException
name = "JuniorClass";
}
public String toString(){
return name.toUpperCase();
}
}
親クラスの SeniorClass
は、オーバライド可能な toString
メソッドを呼び出しているため、サブクラス化によってこの動作を破壊される可能性があります。
サブクラスの JuniorClass
は toString
をオーバライドして、name
フィールドを参照しています。
一方のクラスだけを見ると何も問題ないように見えますが、JuniorClass
のインスタンスを生成しようとすると、SeniorClass
のコンストラクタ経由で JuniorClass#toString()
が呼び出されることになるため、初期化されていない JuniorClass
の name
フィールドが参照されて NullPointerException
が発生します。