CodeQL 文档

构造函数中的非 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

点击查看 CodeQL 存储库中的查询

如果构造函数调用在子类中被重写的方法,则会导致在子类初始化之前调用子类中的重写方法。这会导致意外结果。

建议

如果该方法可能在子类中被重写,请不要在构造函数中调用非 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 方法应设为 finalprivate

  • 可以在子类构造函数本身中执行重写 init 方法中的初始化,或者委托给从子类构造函数中调用的单独的 final 或 private 方法。

参考

  • J. Bloch, *Effective Java(第二版)*,第 89-90 页。Addison-Wesley,2008 年。

  • Java 教程:编写 Final 类和方法

  • ©GitHub, Inc.
  • 条款
  • 隐私