【问题标题】:Why InvalidClassException is not thrown when I have deserialized in the parent class为什么当我在父类中反序列化时不抛出 InvalidClassException
【发布时间】:2021-04-15 02:18:58
【问题描述】:

为什么我在尝试将 Child 类读入 Parent 的类变量时没有错误? 我认为在分配已读取的对象之前,编译器会检查两个类(变量类和已读取的类)的serialVersionUID,如果serialVersionUID 不等于InvalidClassException,则抛出。那么A 类和B 类是否具有相同的serialVersionUID

import java.io.*;

class A  {}

class B extends A implements Serializable {}

public class Test
{
    public static void main(String[] args) throws IOException, ClassNotFoundException
    {
        FileOutputStream fileOutputStream = new FileOutputStream("b.bin");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        B b1 = new B();
        objectOutputStream.writeObject(b1);
        objectOutputStream.close();
        
        FileInputStream fileInputStream = new FileInputStream("b.bin");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        A a1 = (A) objectInputStream.readObject(); // why I don't have an InvalidClass Exception here
        objectInputStream.close();
    }
}

【问题讨论】:

标签: java serialization deserialization


【解决方案1】:

不,这两个类没有相同的serialVersionUID。没有抛出异常,因为类B可以成功重构。例如,当serialVersionUID 不匹配或A 不实现默认构造函数时,会出现InvalidClassException

当您使用objectInputStream.readObject() 反序列化时,会返回一个Object,它可以安全地转换为B。由于B 扩展了A,它可以向上转换为A 类型的对象——就像在您的代码中发生的那样。

顺便说一句,如果您使用序列化直接存储和检索对象,我强烈建议您为您的类定义一个serialVersionUID


你可以得到两个类的serialVersionUID如下:

ObjectStreamClass.lookup(A.class).getSerialVersionUID()
ObjectStreamClass.lookup(B.class).getSerialVersionUID()

【讨论】:

  • 我知道了,但是 JVM 怎么知道我想反序列化哪个类?我的意思是,如果 objectInputStream.readObject() 只看到 serialVersionUID,为什么它会准确返回 B 类?
  • @Denis_newbie 元数据按照Grammar for the Stream Format存储在序列化流中。这包括完整的类名,包括 TC_CLASSDESC 常量之后的包。您可以查看存储的文件 (b.bin) 并检查其内容。一个选项是hexdump -C b.bin
猜你喜欢
  • 2022-11-11
  • 1970-01-01
  • 1970-01-01
  • 2018-12-31
  • 2013-12-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多