为什么在反序列化过程中不调用默认构造函数?

M S*_*ach 3 java serialization

ObjectInputStream is = new ObjectInputStream(new FileInputStream("test.ser"));
TestClass tc = (TestClass)is.readObject();
Run Code Online (Sandbox Code Playgroud)

我在反序列化后得到了TestClass的对象,但是没有调用TestClass的默认构造函数.根据我的理解,有两种方法可以创建对象,即使用new运算符或TestClass.class.newInstance().两者都调用默认构造函数.

看起来像反序列化过程创建对象不是用两个方法,这就是为什么不调用默认构造函数.问题是反序列化如何创建对象?

另一点是,如果TestClass扩展BaseTestClass并且BaseTestClass没有实现序列化,则调用BaseTestClass的构造函数但不调用TestClass.为什么这样 ?我相信它背后会有一些合理的理由.但我没有得到它?

Bra*_*raj 5

值得一读的是Java对象序列化规范:3 - 对象输入类,其中readObject详细描述了方法以及逐步说明.

这个怎么运作?

分配了一个类的实例.实例及其句柄将添加到已知对象集中.

内容适当恢复:

  1. 对于可序列化对象,运行第一个非可序列化超类型的no-arg构造函数.

    • 对于可序列化的类,字段将初始化为适合其类型的默认值.

    • 然后通过调用特定于类的readObject方法来恢复每个类的字段,或者如果未定义这些方法,则通过调用该defaultReadObject方法来恢复.

    • 请注意,在反序列化期间,不会对可序列化类执行字段初始值设定项和构造函数.

    • 在正常情况下,编写流的类的版本将与读取流的类相同.在这种情况下,流中对象的所有超类型都将匹配当前加载的类中的超类型.

    • 如果编写流的类的版本具有与加载的类不同的超类型,则ObjectInputStream必须更加小心地恢复或初始化不同类的状态.

    • 它必须逐步执行这些类,将流中的可用数据与要还原的对象的类进行匹配.流中出现但未在对象中出现的类的数据将被丢弃.

    • 对于在对象中但不在流中出现的类,默认序列化将类字段设置为默认值.

  2. 对于可外部化的对象,运行该类的no-arg构造函数,然后readExternal调用该方法以恢复该对象的内容.


用于理解第一点的示例代码对于可序列化对象,运行第一个非可序列化超类型的无参数构造函数.

示例代码;

class TestClass1 {
    public TestClass1() {
        System.out.println("TestClass1");
    }
}

class TestClass2 extends TestClass1 implements Serializable {
    public TestClass2() {
        System.out.println("TestClass2");
    }
}

public static void main(String[] args) throws Exception {
    System.out.println("Object construction via calling new keyword");
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("resources/dummy.dat"));
    out.writeObject(new TestClass2());

    System.out.println("Object construction via readObject method");
    ObjectInputStream is = new ObjectInputStream(new FileInputStream("resources/dummy.dat"));
    TestClass2 tc = (TestClass2) is.readObject();
}
Run Code Online (Sandbox Code Playgroud)

输出:

Object construction via calling new keyword
TestClass1
TestClass2

Object construction via readObject method
TestClass1
Run Code Online (Sandbox Code Playgroud)