Java –什么是serialVersionUID

在Java中, serialVersionUID类似于版本控制,以确保序列化和反序列化的对象都使用兼容的类。

例如,如果将一个对象保存到具有serialVersionUID=1L的文件(序列化)中,则在将文件转换回一个对象(Derialization)时,必须使用相同的serialVersionUID=1L ,否则InvalidClassException抛出InvalidClassException

Terminal
Exception in thread "main" java.io.InvalidClassException: com.mkyong.io.object.Address;

    local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

1. POJO

查看一个简单的Address类,实现Serializable ,并声明一个serialVersionUID = 1L

Address.java
package com.mkyong.io.object;

import java.io.Serializable;

public class Address implements Serializable {

    private static final long serialVersionUID = 1L;

    String street;
    String country;

    public Address(String street, String country) {
        this.street = street;
        this.country = country;
    }

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "Address{" +
                "street='" + street + '\'' +
                ", country='" + country + '\'' +
                '}';
    }
}

2.测试SerialVersionUID。

2.1将对象保存到文件中,然后将其从文件转换回对象。

ObjectUtils.java
package com.mkyong.io.object;

import java.io.*;

public class ObjectUtils {

    public static void main(String[] args) throws IOException, ClassNotFoundException {

        Address address = new Address("abc", "Malaysia");

        // object -> file
        try (FileOutputStream fos = new FileOutputStream("address.obj");
             ObjectOutputStream oos = new ObjectOutputStream(fos)) {
            oos.writeObject(address);
            oos.flush();
        }

        Address result = null;
        // file -> object
        try (FileInputStream fis = new FileInputStream("address.obj");
             ObjectInputStream ois = new ObjectInputStream(fis)) {
            result = (Address) ois.readObject();
        }

        System.out.println(result);

    }

}

输出量

Terminal
Address{street='abc', country='Malaysia'}

2.2将serialVersionUID更新为99L

Address.java
public class Address implements Serializable {

    private static final long serialVersionUID = 99L;

    String street;
    String country;
    //...

重新运行反序列化过程。

Address result = null;
  // file -> object
  try (FileInputStream fis = new FileInputStream("address.obj");
       ObjectInputStream ois = new ObjectInputStream(fis)) {
      result = (Address) ois.readObject();
  }

  System.out.println(result);

现在,我们点击InvalidClassException

Terminal
Exception in thread "main" java.io.InvalidClassException: com.mkyong.io.object.Address;

  local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 99

  at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:689)
  at java.base/java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1903)
  at java.base/java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1772)
  at java.base/java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2060)
  at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1594)
  at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)

3.我什么时候应该更新serialVersionUID?

例如,当我们修改将破坏与现有序列化对象的兼容性的类时,我们将更新当前的Address类,并添加和删除一些字段。

这项新更改将使所有现有的序列化对象失败,然后我们应该更新serialVersionUID

Address.java
public class Address implements Serializable {

    private static final long serialVersionUID = 9999L;

    String line1;
    String line2;
    Country country;

    //String street;
    //String country;
}

4.默认的serialVersionUID?

如果未声明serialVersionUID ,则JVM将使用其算法生成默认的SerialVersionUID ,请在此处检查算法。 默认的serialVersionUID计算对类详细信息高度敏感,并且可能因不同的JVM实现而异,并且在反序列化过程中会导致意外的InvalidClassExceptions

查看以下示例:

客户端/服务器环境
–客户端在Windows上使用OpenJDK。
–服务器在Linux上使用GraalVM。

客户端将SerialVersionUID=1L的序列化类发送到服务器。 服务器可以使用不同的serialVersionUID=99L反序列化该类,并抛出InvalidClassExceptions 。 由于两者都使用不同的JVM实现,因此它可能在两个站点上生成不同的SerialVersionUID

JVM实现很多

下载源代码

$ git clone https://github.com/mkyong/core-java.git

$ cd java-io

参考文献

翻译自: https://mkyong.com/java-best-practices/understand-the-serialversionuid/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值