Java:为什么反序列化不调用构造函数,最好的解决方法是什么?

Java 1.5 的 Java 序列化规范说:

对于可序列化的对象,将运行第一个不可序列化的超类型的无 arg 构造函数。对于可序列化的类,字段将初始化为适合其类型的默认值。然后,通过调用特定于类的 readObject 方法还原每个类的字段,或者如果未定义这些方法,则通过调用默认的 ReadObject 方法进行还原。请注意,在反序列化期间,不会对可序列化的类执行字段初始值设定项和构造函数。

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

class Foo {
    static int t;

    public Foo() {
        t++;
    }
}

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

    public Bar() {
        t++;
    }
}

在这种情况下,如果 反序列化 了 一个实例,则 的计数器是正确的,而 的计数器是 off-by 1。BarFooBar

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

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

提前感谢您的任何输入!


答案 1

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


答案 2

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

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

推荐