【问题标题】:Adding parameterless constructor to non-serializable, extendable class将无参数构造函数添加到不可序列化的可扩展类
【发布时间】: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


    【解决方案1】:

    我在阅读这本书时遇到了同样的问题。我在那个确切的地方有点困惑。经过一番研究,我发现了这一点。

    http://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

    阅读本文。据此 “在反序列化期间,不可序列化类的字段将使用该类的公共或受保护的无参数构造函数进行初始化。可序列化的子类必须可以访问无参数构造函数。可序列化子类的字段将被恢复来自流”

    我认为这回答了你的问题。 希望这会有所帮助。 如果此评论有任何错误,请随时纠正。

    【讨论】:

      【解决方案2】:

      当您遇到多线程问题时,单独的初始化方法非常有用。好文章可以看:http://www.ibm.com/developerworks/java/library/j-jtp0618/index.html

      【讨论】:

        猜你喜欢
        • 2013-07-29
        • 2017-07-02
        • 1970-01-01
        • 1970-01-01
        • 2017-09-12
        • 1970-01-01
        • 2015-08-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多