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属性不会进行序列化处理。

总结

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

相关文章

  • mac下idea的svn密码记不住的问题及处理方法

    mac下idea的svn密码记不住的问题及处理方法

    这篇文章主要介绍了mac下idea的svn密码记不住的问题及处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-09-09
  • java实现web实时消息推送的七种方案

    java实现web实时消息推送的七种方案

    这篇文章主要为大家介绍了java实现web实时消息推送的七种方案示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-07-07
  • springboot线程池监控的简单实现

    springboot线程池监控的简单实现

    本文主要介绍了springboot线程池监控的简单实现,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • 使用Mybatis-plus实现时间自动填充(代码直接可用)

    使用Mybatis-plus实现时间自动填充(代码直接可用)

    这篇文章主要介绍了使用Mybatis-plus实现时间自动填充(代码直接可用),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • Java语言实现简单FTP软件 FTP软件效果图预览之下载功能(2)

    Java语言实现简单FTP软件 FTP软件效果图预览之下载功能(2)

    这篇文章主要为大家详细介绍了Java语言实现简单FTP软件,FTP软件效果图预览之下载功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-03-03
  • HashMap的底层实现原理分析

    HashMap的底层实现原理分析

    本文主要介绍了HashMap的底层实现结构,包括JDK1.7和1.8版本的区别,JDK1.7使用数组加链表实现,而JDK1.8引入了红黑树优化,文章详细解释了HashMap如何确定哈希桶数组索引位置、put方法的执行过程以及扩容原理
    2025-01-01
  • java面向对象设计原则之开闭原则示例解析

    java面向对象设计原则之开闭原则示例解析

    这篇文章主要介绍了java面向对象设计原则之开闭原则的示例解析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2021-10-10
  • Java spring 通过注解方式创建对象的示例详解

    Java spring 通过注解方式创建对象的示例详解

    这篇文章主要介绍了java spring 通过注解方式创建对象,本文结合示例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-02-02
  • SpringBoot项目使用validated实现参数校验框架

    SpringBoot项目使用validated实现参数校验框架

    当谈到Spring的参数校验功能时,@Validated注解无疑是一个重要的利器,它为我们提供了一种简单而又强大的方式来验证请求参数的合法性,保证了系统的稳定性和安全性,本文将介绍Spring Validated的基本用法以及在实际项目中的应用,需要的朋友可以参考下
    2024-05-05
  • spring四种依赖注入方式的详细介绍

    spring四种依赖注入方式的详细介绍

    本篇文章主要介绍了spring四种依赖注入方式的详细介绍,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-02-02

最新评论