编写可序列化的子类

时间:2015-12-08 06:56:11

标签: java serialization

我正在阅读J. Bloch的有效Java,现在我正在阅读关于序列化的部分。他说那个

  

如果为继承而设计的类不可序列化,那么   可能无法编写可序列化的子类。具体来说,   如果超类不提供可访问的,将是不可能的   无参数构造函数

我不明白这种限制。我在以下课程中尝试了这个:

private static class Base {

    private int i;
    private Object o;

    public Base(int i, Object o){
        if(i == 0 || o == null)
            throw new IllegalArgumentException("The arguments are not accepted by this constructor");
        this.i = i;
        this.o = o;
    }

    private void readObjectNoData() throws InvalidObjectException{
        throw new InvalidObjectException("Stream data required");
    }
}

private static class Derived extends Base implements Serializable{

    public Derived(int i, Object o) {
        super(i, o);
    }

    private static final long serialVersionUID = 1L;
}

实际上,我可以序列化Derived的一个实例,但是当我试图想要它时,我得到了例外:

java.io.InvalidClassException: com.pack.age.SerializableTest$Derived; no valid constructor

你不能解释这些事情的重点吗?在这种情况下,我不明白他们为什么需要无参数构造函数。

3 个答案:

答案 0 :(得分:3)

当Java创建Derived对象(通过任何方式)时,它必须能够正确初始化Base类的状态。当您使用new Derived(0, null)时,Derived的构造函数知道要调用Base的哪个构造函数以确保Base已正确设置。

反序列化对象时,Java不使用构造函数;它使用单独的后门机制来设置Serializable对象的状态。但是,在这种情况下,JVM不知道如何调用超类构造函数;它唯一能做的就是调用一个无参数的构造函数(这样类可以适当地初始化它自己的私有字段)。

Base可能有某种内部状态(保留在私有字段中)Derived无法看到。此状态未被序列化(因为Base没有实现Serializable),并且没有构造函数来设置它,对象的Base部分可能在不一致的状态。

答案 1 :(得分:2)

api:https://docs.oracle.com/javase/7/docs/api/java/io/Serializable.html

也需要它
  

要允许序列化非序列化类的子类型,   子类型可能承担保存和恢复状态的责任   超类型的公共,受保护和(如果可访问)包   领域。只有在类中,子类型才可以承担此责任   它扩展了一个可访问的无参数构造函数来初始化   阶级的国家。如果这样,声明一个Serializable类是错误的   事实并非如此。将在运行时检测到错误。

     

在反序列化期间,非序列化类的字段将是   使用公共或受保护的无参数构造函数初始化   类。必须可以访问子类的无参数构造函数   序列化。将恢复可序列化子类的字段   来自溪流。

从文件中反序列化对象时,需要能够实例化对象。如果您有多参数constructor,您将不知道如何实例化它(传递给它的内容)。

答案 2 :(得分:1)

如果要反序列化对象,则需要一个无参数构造函数。

除此之外

public Base(int i, Object o)

添加无参数构造函数,如

public Base()