java对象序列化为什么要使用SerialversionUID

java对象序列化为什么要使用SerialversionUID

首先谈谈问什么要序列化对象?

  • 把对象转换为字节序列的过程称为对象的序列化
  • 把字节序列恢复为对象的反序列化

对象序列化主要有两种用途:

  1. 把对象的字节序列永久的保存到硬盘上,通常存放在一个文件中
  2. 在网络上传送对象的字节序列

在很多应用中,需要对某些对象进行序列化,让他们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的就说web服务器中的session对象,当有10w用户并发访问,就有可能出现10w个session对象,内存可能吃不消,于是web容器就会把一些session先序列化到硬盘中,等要用了,再把保存再硬盘中的对象还原到内存中

当两个进程再进行远程通信的时候,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式再网络上传送,发送方需要把这个java对象转换为字节序列,才能再网络上传送,接收方则需要把字节序列再恢复为java对象

为什么要用SerialversionUID呢?

简单看下Serializable接口的说明

If a serializable class does not explicitly declare a serialVersionUID,
   then the serialization runtime will calculate a default 
   serialVersionUID value for that class based on various aspects of the class, 
  as described in the Java(TM) Object Serialization Specification. 

如果用户没有自己声明一个SerialversionUID,接口会默认生成一个SerialversionUID

但是,非常强烈建议用户自己定义一个SerialversionUID,因为默认的SerialversionUID对于class的细节非常敏感,反序列化的时候可能会导致InvalidClassException这个异常

使用默认的SerialversionUID

public class Person implements Serializable {

    private int age;
    private String name;
    private String sex;

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }


    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

然后去序列化和反序列化

public class TestSerialversionUID {

    public static void main(String[] args) throws Exception {
        serializablePerson();
        Person person=deserializablePerson();
        System.out.println(person.getName()+"  "+ person.getAge());
    }

    private static void serializablePerson() throws Exception{

        Person person=new Person();
        person.setName("测试实例");
        person.setAge(21);
        person.setSex("male");

        ObjectOutputStream oos = new ObjectOutputStream
                (new FileOutputStream(new File("E:/person.txt")));
        oos.writeObject(person);
        System.out.println("序列化成功");
        oos.close();

    }

    private static Person deserializablePerson() throws Exception {
        ObjectInputStream ois = new ObjectInputStream
                (new FileInputStream(new File("E:/person.txt")));
        Person person=(Person)ois.readObject();
        System.out.println("反序列化成功");
        ois.close();
        return person;
    }
}

测试结果如下图:

序列化成功
反序列化成功
测试实例  21

如果我们先尽心序列化,然后再反序列化之前修改了Person类会怎么样呢?

/**
 * @author wcc
 * @date 2021/8/18 20:05
 */
public class Person implements Serializable {

    private int age;
    private String name;
    private String sex;
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

fz7aWt.png

可以看到,当我们子反序列化之前修改Person类的时候,Person类对应的SerialversionUID也变化了,而序列化和反序列化就说通过对比其SerialversionUID来进行的,一旦SerialversionUID不匹配,反序列化就无法成功。再实际的生产环境中,我们可能会建一系列的中间Object来反序列化我们的pojo,为了解决这个问题,我们就需要再实体类中自定义SerialversionUID。

在Person类中加入自定义SerialversionUID

public class Person implements Serializable {

    private static final long serialVersionUID = -5809782578272943999L;

    private int age;
    private String name;
    private String sex;
    private String address;

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    /*@Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", sex='" + sex + '\'' +
                '}';
    }*/

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    public String getName(){
    	return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}    
不管我们序列化之后如何更改我们的Person类(不删除原有字段),最终都可以反序列化成功。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值