【问题标题】:Serialization with Inheritance (Java)继承序列化 (Java)
【发布时间】:2018-04-15 14:09:02
【问题描述】:

我正在学习序列化和继承,但我不明白在反序列化过程中谁调用了无参数构造函数。超类 A 不实现 Serializable,子类 B 扩展 A 实现 Serializable。

超类 A

public class A {

    int i;

    public A(int i) 
    {
        this.i = i;
    }

    public A()
    {
        i = 50;
        System.out.println("A's class constructor called");
    }  
}

子类 B

import java.io.Serializable;

public class B extends A implements Serializable {

    int j;

    // parameterized constructor
    public B(int i,int j) 
    {
        super(i);
        this.j = j;
    }
}

驱动类

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Test {

    public static void main(String[] args) throws Exception {

        B b1 = new B(10,20);

        System.out.println("i = " + b1.i);
        System.out.println("j = " + b1.j);

        // Serializing B's(subclass) object 

        //Saving of object in a file
        FileOutputStream fos = new FileOutputStream("abc.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);

        // Method for serialization of B's class object
        oos.writeObject(b1);

        // closing streams
        oos.close();
        fos.close();

        System.out.println("Object has been serialized");

        // De-Serializing B's(subclass) object 

        // Reading the object from a file
        FileInputStream fis = new FileInputStream("abc.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);

        // Method for de-serialization of B's class object
        B b2 = (B)ois.readObject();  // The A() constructor is called here

        // closing streams
        ois.close();
        fis.close();

        System.out.println("Object has been deserialized");

        System.out.println("i = " + b2.i);
        System.out.println("j = " + b2.j);
    }
}

如果我删除 A() 构造函数,我会得到 InvalidClassException。我看到在创建 b2 对象时调用了 A() 但我不明白为什么在此语句中调用此 A() 以及是谁调用了它。

当创建 b1 对象时,会调用 B(int i, int j) 构造函数和 A(int i) 构造函数。这很容易理解。但我不明白为什么在创建 b2 对象时调用 A() 构造函数。

【问题讨论】:

标签: java inheritance serialization constructor deserialization


【解决方案1】:

来自Serializable JavaDocs

为了允许对不可序列化类的子类型进行序列化,子类型可能会负责保存和恢复超类型的公共、受保护和(如果可访问)包字段的状态。只有当它扩展的类具有可访问的无参数构造函数来初始化类的状态时,子类型才可以承担此责任。如果不是这种情况,则声明一个类 Serializable 是错误的。将在运行时检测到错误。

现在回答你的问题:

如果我删除 A() 构造函数,我会得到 InvalidClassException。我看到在创建 b2 对象时调用了 A(),但我不明白为什么在此语句中调用此 A() 以及是谁调用了它。

A() 构造函数由序列化机制通过反射调用。具体来自ObjectInputStream 通过ObjectStreamClass

【讨论】:

    【解决方案2】:

    因为 A 类是不可序列化的。

    在 java 中,当您创建一个对象时,会创建一个对象树,其中包含层次结构中的所有对象。在你的情况下 B -> A -> 对象。

    序列化的目的是存储对象的状态,以便以后使用。

    当你反序列化它时,java 会创建一个新对象而不调用构造函数。如果构造函数被调用,对象将失去其状态(它可能初始化为其默认值)。

    由于类 A 不可序列化,这意味着它的状态不会被保存,java 将在反序列化期间通过调用默认构造函数来创建一个新对象。如果没有找到默认构造函数,反序列化时会抛出异常。

    如果你想避免这种情况,请阅读 writeReplace() 和 readResolve() 方法

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 1970-01-01
      • 2013-12-28
      • 2010-12-15
      相关资源
      最近更新 更多