我正在阅读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
你不能解释这些事情的重点吗?在这种情况下,我不明白他们为什么需要无参数构造函数。
答案 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()