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

发布于 2024-11-30 23:57:59 字数 879 浏览 2 评论 0原文

Java 1.5 的 Java 序列化规范 说:

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

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

class Foo {
    static int t;

    public Foo() {
        t++;
    }
}

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

    public Bar() {
        t++;
    }
}

在这种情况下,如果 Bar 的一个实例被反序列化,则Foo 的计数器正确,Bar 的计数器相差一。

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

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

感谢您提前提供任何意见!

The Java serialization spec for Java 1.5 said:

For serializable objects, the no-arg constructor for the first
non-serializable supertype is run. For serializable classes, the
fields are initialized to the default value appropriate for its type.
Then the fields of each class are restored by calling class-specific
readObject methods, or if these are not defined, by calling the
defaultReadObject method. Note that field initializers and
constructors are not executed for serializable classes during
deserialization.

However, this means if we put a static variable (for example a counter variable) inside the class, it will not be updated as normally would:

class Foo {
    static int t;

    public Foo() {
        t++;
    }
}

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

    public Bar() {
        t++;
    }
}

In this case, if one instance of Bar is deserialized, then the counter for Foo is correct and the counter for Bar is off-by-one.

I wonder why does deserialization does not invoke the constructor? Since it seems that while this will gain a bit on speed, it can cause potential problems. The compiler could be easily designed to produce a "static constructor" that only updates the static variables that will be updated and does not rely on outside information when the class is loaded.

Also, I wonder what is the best way to avoid this? The solution I can think of is packing the deserialization with the operation on the static variable.

Thanks for any inputs in advance!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

薄荷港 2024-12-07 23:57:59

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

Deserialization doesn't invoke the constructor because the purpose of it is to express the state of the object as it was serialized, running constructor code could interfere with that.

烟酉 2024-12-07 23:57:59

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

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

Without going in to the philosophy of why a constructor is not called (objects without default constructors, for example, should be Serializable) the standard way of working around problems with the default behavior is to provide your own readObject() or writeObject() implementations for your class.

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException
{
    in.defaultReadObject();
    t++;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文