【发布时间】:2016-11-11 09:59:17
【问题描述】:
如果 Java 类有一个被延迟或按需初始化的字段,我们如何确保通过它的初始化访问方法访问惰性字段?
作为上下文,我们最近遇到了这样一种情况,开发人员添加了对延迟初始化的对象的访问,但不是通过其初始化访问方法。这在编译或单元测试中没有发现,但随后导致了运行时错误。
例如 - 在下面的 SSCCE 中,_lazyObject 是通过 getLazyObject() 方法初始化的。但是,如果有其他方法(在类中,因为它已经有一个private 访问修饰符)想要使用_lazyObject,我们应该通过getLazyObject() 方法访问,否则它可能没有被初始化.
public class MyObject {
private transient volatile Object _lazyObject;
public Object getLazyObject() {
if (_lazyObject == null) {
synchronized (this) {
if (_lazyObject == null) {
_lazyObject = new Object();
}
}
}
return _lazyObject;
}
public void doSomething() {
Object a = _lazyObject; // may be null - will compile, but may cause runtime errors!
Object b = getLazyObject(); // subject to exceptions, will not be null - this is how it should be accessed.
// do something...
}
}
如何保证_lazyObject的访问是通过getLazyObject()?
- 这在
MyObject中的代码中是否可行? - 或者,是否可以通过单元测试来确保这一点?
【问题讨论】:
-
您可以包含断言以检查
_lazyObject是否已实例化assert _lazyObject != null : "Use getLazyObject()!"以进行单元测试。我假设MyObject有一个私有构造函数来阻止其他类实例化MyObject,尽管这不是你的问题。 -
惰性对象真的是 Object 类型还是更具体?
-
@Gimby - 它总是更具体。我们非常广泛地使用延迟初始化——尤其是在序列化类/跨 JVM 共享时,因此它通常是太大而无法序列化(即重新初始化更快)或无法序列化的东西。
-
@d.j.brown - MyObject 只是这个 SO 问题的一个例子。
-
@d.j.brown - 你能详细说明你的建议吗?你建议断言应该去哪里,这如何解决问题?