将addid无参数构造函数添加到不可序列化的可扩展类中有什么特别之处。
在Effective java中,作者讨论了这个主题。
天真地添加一个无参数构造函数和一个 将初始化方法分离到剩余构造函数建立其类的类 不变量会使状态空间复杂化,增加出错的可能性。
从Effective Java 2nd Edition [页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)。这对于确保对象的完整性是必要的 面对坚定的对手。在没有这种预防措施的情况下,如果有一个线程 在第二个线程试图使用时调用实例上的初始化 它,第二个线程可能会看到实例处于不一致状态。
我们为什么要这样做?我没有完全理解这一点。谁能解释一下?
答案 0 :(得分:3)
我在阅读这本书时遇到了同样的问题。我在那个确切的地方有点困惑。通过一些研究,我发现了这一点。
http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html
阅读本文。根据那个 “在反序列化期间,非序列化类的字段将使用类的public或protected no-arg构造函数进行初始化。对于可序列化的子类,必须可以访问no-arg构造函数。可序列化子类的字段将被恢复来自流“
我认为这可以回答你的问题。 希望这会有所帮助。 如果此评论中有任何错误,请随时更正。
答案 1 :(得分:0)
当您遇到多线程问题时,单独的初始化方法非常有用。你可以看到好文章:http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html