【发布时间】:2011-12-26 04:58:13
【问题描述】:
将无参数构造函数添加到不可序列化、可扩展的类有什么特别之处。
在 Effective java 中,作者谈到了这个话题。
天真地添加一个无参数的构造函数和一个 一个类的单独初始化方法,其其余构造函数建立它的 不变量会使状态空间复杂化,增加出错的可能性。
以下代码复制自 Effective Java 2nd Edition[Page 292-293]
public class AbstractFoo {
private int x, y; // Our state
// This enum and field are used to track initialization
private enum State {
NEW, INITIALIZING, INITIALIZED
};
private final AtomicReference<State> init = new AtomicReference<State>(
State.NEW);
public AbstractFoo(int x, int y) {
initialize(x, y);
}
// This constructor and the following method allow
// subclass's readObject method to initialize our state.
protected AbstractFoo() {
}
protected final void initialize(int x, int y) {
if (!init.compareAndSet(State.NEW, State.INITIALIZING))
throw new IllegalStateException("Already initialized");
this.x = x;
this.y = y;
// ... // Do anything else the original constructor did
init.set(State.INITIALIZED);
}
// These methods provide access to internal state so it can
// be manually serialized by subclass's writeObject method.
protected final int getX() {
checkInit();
return x;
}
protected final int getY() {
checkInit();
return y;
}
// Must call from all public and protected instance methods
private void checkInit() {
if (init.get() != State.INITIALIZED)
throw new IllegalStateException("Uninitialized");
}
// ... // Remainder omitted
}
AbstractFoo 中的所有公共和受保护的实例方法都必须调用 checkInit 在做任何其他事情之前。这确保方法调用失败 如果写得不好的子类无法初始化实例,则可以快速而干净地。笔记 初始化字段是原子引用(java.util.concurrent. atomic.AtomicReference)。这是确保对象完整性所必需的 面对坚定的对手。在没有这种预防措施的情况下,如果一个线程 当第二个线程试图使用时,要在实例上调用初始化 它,第二个线程可能会看到实例处于不一致的状态。
我们为什么要这样做?我没有完全理解这一点。谁能解释一下?
【问题讨论】:
标签: java serialization