【问题标题】:Java: Why doesn't deserialization invoke constructor & what's the best workaround?Java:为什么反序列化不调用构造函数&最好的解决方法是什么?
【发布时间】:2011-08-22 18:14:59
【问题描述】:

Java 1.5 的Java serialization spec 说:

对于可序列化的对象,第一个的无参数构造函数 运行不可序列化的超类型。对于可序列化的类, 字段被初始化为适合其类型的默认值。 然后通过调用class-specific来恢复每个类的字段 readObject 方法,或者如果未定义这些方法,则通过调用 默认读取对象方法。请注意,字段初始值设定项和 期间不为可序列化的类执行构造函数 反序列化。

但是,这意味着如果我们在类中放置一个静态变量(例如计数器变量),它将不会像往常一样被更新:

class Foo {
    static int t;

    public Foo() {
        t++;
    }
}

public class Bar extends Foo implements Serializable {
    static int t;

    public Bar() {
        t++;
    }
}

在这种情况下,如果 Bar 的一个实例被反序列化,则 @​​987654324@ 的计数器是正确的,Bar 的计数器是关闭的。

我想知道为什么反序列化不调用构造函数?因为看起来虽然这会提高速度,但它可能会导致潜在的问题。编译器可以很容易地设计为生成一个“静态构造函数”,它只更新将要更新的静态变量,并且在加载类时不依赖外部信息。

另外,我想知道避免这种情况的最佳方法是什么?我能想到的解决方案是将反序列化与静态变量的操作打包在一起。

提前感谢您的任何意见!

【问题讨论】:

  • 我无法想象我的回答是你想听到的,抱歉我帮不上忙。您有一个观点,序列化的整个设计似乎取决于不可序列化的超类构造函数,它们没有您描述的那种副作用。但我很难想象会发生此问题的现实世界情况。

标签: java inheritance constructor deserialization


【解决方案1】:

反序列化不会调用构造函数,因为它的目的是在对象被序列化时表达对象的状态,运行构造函数代码可能会干扰它。

【讨论】:

    【解决方案2】:

    如果不深入探讨为什么不调用构造函数(例如,没有默认构造函数的对象应该是可序列化的),解决默认行为问题的标准方法是提供您自己的 readObject() 或 writeObject () 类的实现。

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        t++;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-10-16
      • 2019-09-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-23
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多