【问题标题】:Writing serializable subclass [duplicate]编写可序列化的子类
【发布时间】:2016-03-13 00:18:06
【问题描述】:

我正在阅读 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

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

【问题讨论】:

  • 因为代码试图在内存中重建一个类,部分要求是它有一个无参数的公共构造函数

标签: java serialization


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

      【解决方案3】:

      如果你想反序列化对象,你需要一个可以调用的无参数构造函数。

      所以除了你的

      public Base(int i, Object o)
      

      添加一个无参数构造函数,如

      public Base()
      

      【讨论】:

        猜你喜欢
        • 2011-12-01
        • 1970-01-01
        • 2013-02-04
        • 2016-05-22
        • 1970-01-01
        • 1970-01-01
        • 2016-08-30
        • 1970-01-01
        相关资源
        最近更新 更多