Java序列化之serialVersionUID的用法解读

 更新时间:2025年11月21日 10:46:24   作者:红提口味趣多多  
Java序列化之serialVersionUID:本文介绍了Java对象的序列化和反序列化过程,强调了serialVersionUID的作用,以及如何生成和使用它来保证版本兼容性,通过实例代码,展示了序列化和反序列化的具体操作

Java序列化之serialVersionUID

今天讲一讲Java对象中的serialVersionUID,先从序列化讲起。

什么是序列化

序列化,简单的说,就是将一个对象转化(编码)成可以传输的输出流(字节流)。而反序列化就是序列化的逆过程,将输入流转化(构建)成一个对象。

为什么要序列化

字节流可以用于网络传输和存储在磁盘,而对象需要转化成字节流才能在网络中传输和在磁盘上存储。

网络传输就好比打电话,声音是无法直接从电话的一端传到另一端,因此需要将声音转成电信号进行传播。

另一方面,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了,而序列化提供了可以把对象保存下来的方案。

serialVersionUID是个啥

说到序列化,serialVersionUID是个不得不谈的话题。

serialVersionUID 是 Java 为每个序列化类(实现java.io.Serializable接口的类)产生的版本标识, 可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。

如果接收方接收的类的 serialVersionUID 与发送方发送的 serialVersionUID 不一致,进行反序列时会抛出 InvalidClassException。

怎么生成serialVersionUID

下载GenerateSerialVersionUID插件,就可以自动生产这个序列类的serialVersionUID了。

serialVersionUID是一成不变的吗

达咩! 

serialVersionUID 是 Java 为每个序列化类产生的版本标识!!

Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用。

如果Class文件的类名、方法名称发生改变,serialVersionUID就会改变。

如果Class文件没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。

import java.io.Serializable;

public class Person implements Serializable {
    // 原本的serialVersionUID
    private static final long serialVersionUID = 904XXXXXXXXXX662L;

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

    public Person(int age, String name, String address) {
        this.age = age;
        this.name = name;
        this.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 getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

import java.io.Serializable;

public class Person implements Serializable {
    // 加上toSting函数的serialVersionUID
    private static final long serialVersionUID = 841XXXXXXXXXXXXX884L;

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

    public Person(int age, String name, String address) {
        this.age = age;
        this.name = name;
        this.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 getAddress() {
        return address;
    }

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

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

如果我手动改了serialVersionUID=11111111L会怎样?如果接收方接收的类的 serialVersionUID 与发送方发送的 serialVersionUID 不一致,进行反序列时会抛出 InvalidClassException。

Exception in thread "main" java.io.InvalidClassException: SerializableStudy.Person; local class incompatible: stream classdesc serialVersionUID = 841XXXXXXXXXXXXX884, local class serialVersionUID = 11111111

序列化和反序列化

序列化要把对象写入输出流中,反序列化就是将输出流重新构建对象,二者为逆过程。当serialVersionUID改变时,一定要重新序列化,再进行反序列化。

话不多说,放代码。

以下是基于上面序列化类Person,做序列化和反序列化的演示:

public class SerialTest {

    public static void main(String[] args) throws IOException {
//        序列化
        Person p = new Person(0,"aaa","bbbbb");
//        指定文件生成输出流
        FileOutputStream fos = new FileOutputStream("person.txt");
//        将对象写出到指定的输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);
//        将指定的对象写入ObjectOutputStream。
        oos.writeObject(p);
//        刷新流
        oos.flush();
        oos.close();
    }
}
public class DeserialTest {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        反序列化
//        根据指定文件生产输入流
        FileInputStream fis = new FileInputStream("person.txt");
//        从指定的输入流中读回对象消息
        ObjectInputStream ois = new ObjectInputStream(fis);
//        从ObjectInputStream读取一个对象
        Person p = (Person) ois.readObject();
        ois.close();
        System.out.println(p.toString());
    }
}

输出的结果为:

注意:

将指定对象写入ObjectOutputStream时,存储针对对象本身而不是针对类,没有实现序列化的类不会参与序列化和反序列化!!

举个例子,如果Person中设置一个没有实现序列化的父类Home:

public class Home {
    private String home;

    public String getHome() {
        return home;
    }

    public void setHome(String home) {
        this.home = home;
    }
}
public class Person extends Home implements Serializable {
	......
}

在序列化和反序列化的过程中,即使定义了Person对象的home属性,由于Home中没有实现序列类,因此对象的home属性不会进行序列化处理。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • SpringBoot如何切换成其它的嵌入式Servlet容器(Jetty和Undertow)

    SpringBoot如何切换成其它的嵌入式Servlet容器(Jetty和Undertow)

    这篇文章主要介绍了SpringBoot如何切换成其它的嵌入式Servlet容器(Jetty和Undertow),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-07-07
  • RocketMQ NameServer架构设计启动流程

    RocketMQ NameServer架构设计启动流程

    这篇文章主要为大家介绍了RocketMQ NameServer架构设计启动流程,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-02-02
  • Spring中循环依赖的解决方法详析

    Spring中循环依赖的解决方法详析

    这篇文章主要给大家介绍了关于Spring中循环依赖的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用spring具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • java 数据的加密与解密普遍实例代码

    java 数据的加密与解密普遍实例代码

    本篇文章介绍了一个关于密钥查询的jsp文件简单实例代码,需要的朋友可以参考下
    2017-04-04
  • MyBatis执行SQL查询的完整流程

    MyBatis执行SQL查询的完整流程

    本文详细介绍了MyBatis SQL执行的完整过程,包括核心对象、代码实现与执行链路,通过编程式调用示例和流程图,展示了从环境配置、SqlSession创建到结果获取的全步骤,需要的朋友可以参考下
    2026-01-01
  • Spring Security 在 Spring Boot 中的使用详解【集中式】

    Spring Security 在 Spring Boot 中的使用详解【集中式】

    这篇文章主要介绍了Spring Security 在 Spring Boot 中的使用【集中式】,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-10-10
  • java基于servlet实现文件上传功能解析

    java基于servlet实现文件上传功能解析

    这篇文章主要为大家详细介绍了java基于servlet实现上传功能,后台使用java实现,前端主要是js的ajax实现,感兴趣的小伙伴们可以参考一下
    2016-05-05
  • SpringBoot中@Value获取值和@ConfigurationProperties获取值用法及比较

    SpringBoot中@Value获取值和@ConfigurationProperties获取值用法及比较

    在Spring Boot中,@Value注解是一个非常有用的特性,它允许我们将外部的配置注入到我们的Bean中,@ConfigurationProperties用于将配置文件中的属性绑定到 Java Bean 上,本文介绍了@Value获取值和@ConfigurationProperties获取值用法及比较,需要的朋友可以参考下
    2024-08-08
  • Java单测void类型的方法详解

    Java单测void类型的方法详解

    这篇文章主要给大家介绍了Java中单测void类型的方法,文中给出了详细的示例代码,相信对大家的理解和学习具有一定的参考借鉴价值,需要的朋友可以跟着小编下面来一起学习学习吧。
    2017-01-01
  • Spring MVC传递接收参数方式小结

    Spring MVC传递接收参数方式小结

    大家在开发中经常会用到Spring MVC Controller来接收请求参数,主要常用的接收方式就是通过实体对象以及形参等方式、有些用于GET请求,有些用于POST请求,有些用于两者,下面介绍几种常见的Spring MVC传递接收参数的方式
    2021-11-11

最新评论