详解Java中的serialVersionUID概念以及作用(附上Demo)

2024-01-09 10:20

本文主要是介绍详解Java中的serialVersionUID概念以及作用(附上Demo),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 前言
  • 1. 概念
  • 2. Demo

前言

原本实现Serializable接口的时候一直都没有serialVersionUID属性,直到看到涉及MybatisPlus新项目中都有该属性,于是做了一期学习了解,最后发现该属性类似深度学习训练中的种子seed,类似版本控制!

1. 概念

serialVersionUID 是 Java 中用于版本控制序列化的一个字段。

手动方式默认值为1L,比如:private static final long serialVersionUID = 1L

  • 一个长整型数值
  • 是一个 private static final long 类型的字段,用于标识一个类的序列化版本号
  • 在序列化和反序列化过程中,serialVersionUID 被用来验证序列化对象和反序列化对象的类是否兼容,即是否是同一个类的不同版本。
作用(为什么需要)生成方式(功能意义)注意事项
1.用于标识类的版本,确保序列化和反序列化的兼容性。如果两个类的 serialVersionUID 不同,Java 将不会进行序列化和反序列化,以避免版本不一致导致的问题。

2.冲突解决: 在类的结构发生变化时,通过手动指定 serialVersionUID 可以防止默认生成的版本号发生变化,从而避免潜在的冲突。
1.自动生成: 如果一个类没有显式声明 serialVersionUID,Java 序列化机制会根据类的结构自动生成一个版本号。

2.手动生成: 开发人员可以通过手动在类中定义 private static final long serialVersionUID 来指定版本号,以便在类结构发生变化时能够更加精确地控制版本。
1.如果不显式指定 serialVersionUID,Java 将根据类的结构自动生成。这种自动生成的方式可能不够稳定,因此在需要进行序列化的类中最好显式指定 serialVersionUID。

2.当类的结构发生变化时,手动指定 serialVersionUID 可以防止默认生成的版本号发生变化,避免潜在的序列化问题。

类似的代码如下:

import java.io.Serializable;public class MyClass implements Serializable {private static final long serialVersionUID = 1L;// other class members and methods
}

在这个示例中,MyClass 类显式地指定了 serialVersionUID 为 1L,以确保在类的结构发生变化时能够更好地进行版本控制

对于Serializable 类,其源码只是一个接口:public interface Serializable { }

总的来说:

serialVersionUID 是根据类的结构计算得到的哈希值,通常为负数。这个值是通过对类的结构进行哈希运算而生成的,因此不同版本的类将具有不同的 serialVersionUID。其存在的主要目的是为了处理序列化和反序列化过程中的版本兼容性问题。

当一个类被序列化后,其字节表示可能会存储在磁盘上或通过网络传输到不同的 JVM(Java 虚拟机)。如果类的结构发生了变化,例如添加了新的字段或方法,反序列化时就可能出现版本不一致的问题。为了解决这个问题,引入了 serialVersionUID 的概念。

以下是对 serialVersionUID 的功能和作用的总结:

  • 版本兼容性
    serialVersionUID 的存在是为了确保序列化和反序列化的版本兼容性。
    当类的结构发生变化时,不同版本的类将具有不同的 serialVersionUID。
    在序列化和反序列化过程中,Java 使用 serialVersionUID 来验证类的版本是否一致,以防止版本不匹配引发的问题。

  • 自动生成和手动生成:(上述已阐述)

  • 兼容性处理:
    当反序列化旧版本的对象时,如果新版本的类中删除了某些字段或方法,Java 虚拟机会忽略这些字段或方法,而不会引发异常。
    这种处理方式允许在一定程度上保持不同版本的类的兼容性,使得应用程序在进行升级时更加灵活。

总体而言,serialVersionUID 是一个重要的概念,用于确保序列化和反序列化过程中类的版本兼容性,同时提供了灵活的手动生成方式,使开发人员能够更好地控制类的版本信息。

2. Demo

为了更加方便的显示serialVersionUID的作用,可看下方的例子

原本Entity中有一个实体类,实现了Serializable 类

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("test_user")
public class User implements Serializable {private static final long serialVersionUID = 1L;@TableId(value = "id", type = IdType.AUTO)private int id;private String username;private String password;// 其他字段...}

通过序列化User的对象,并再次反序列化读取对象:

import java.io.*;public class SerializationDemo {// 序列化对象public static void serializeUser(User user, String filename) throws IOException {try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(filename))) {out.writeObject(user);}}// 反序列化读取对象public static User deserializeUser(String filename) throws IOException, ClassNotFoundException {try (ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename))) {return (User) in.readObject();}}public static void main(String[] args) throws IOException, ClassNotFoundException {// 创建一个 User 对象并序列化保存User user = new User(123,"manong", "123");serializeUser(user, "user.ser");// 反序列化读取 Person 对象User deserializedPerson = deserializeUser("user.ser");System.out.println("Deserialized User: " + deserializedPerson);}
}

执行得到的结果为:Deserialized User: User(id=123, username=manong, password=123)

截图如下:

在这里插入图片描述


如果在此时修改版本(假设开发者不知道其版本),并且增加属性:

@Data
@AllArgsConstructor
@NoArgsConstructor
@TableName("test_user")
public class User implements Serializable {// 修改位置private static final long serialVersionUID = 2L;@TableId(value = "id", type = IdType.AUTO)private int id;private String username;private String password;// 其他字段...private String ceshi;}

对应反序列化改为如下:

    public static void main(String[] args) throws IOException, ClassNotFoundException {// 创建一个 User 对象并序列化保存
//        User user = new User(123,"manong", "123");
//        serializeUser(user, "user.ser");try {// 反序列化读取 Person 对象User deserializedPerson = deserializeUser("user.ser");System.out.println("Deserialized User: " + deserializedPerson);}catch (IOException | ClassNotFoundException e) {System.err.println("Error deserializing: " + e.getMessage());}}

根绝提示bug,也可看出不匹配:

Error deserializing: com.example.demo.entity.User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

截图如下:

在这里插入图片描述

这篇关于详解Java中的serialVersionUID概念以及作用(附上Demo)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/586793

相关文章

Java实现字节字符转bcd编码

《Java实现字节字符转bcd编码》BCD是一种将十进制数字编码为二进制的表示方式,常用于数字显示和存储,本文将介绍如何在Java中实现字节字符转BCD码的过程,需要的小伙伴可以了解下... 目录前言BCD码是什么Java实现字节转bcd编码方法补充总结前言BCD码(Binary-Coded Decima

Redis 的 SUBSCRIBE命令详解

《Redis的SUBSCRIBE命令详解》Redis的SUBSCRIBE命令用于订阅一个或多个频道,以便接收发送到这些频道的消息,本文给大家介绍Redis的SUBSCRIBE命令,感兴趣的朋友跟随... 目录基本语法工作原理示例消息格式相关命令python 示例Redis 的 SUBSCRIBE 命令用于订

SpringBoot全局域名替换的实现

《SpringBoot全局域名替换的实现》本文主要介绍了SpringBoot全局域名替换的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录 项目结构⚙️ 配置文件application.yml️ 配置类AppProperties.Ja

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解

《使用Python批量将.ncm格式的音频文件转换为.mp3格式的实战详解》本文详细介绍了如何使用Python通过ncmdump工具批量将.ncm音频转换为.mp3的步骤,包括安装、配置ffmpeg环... 目录1. 前言2. 安装 ncmdump3. 实现 .ncm 转 .mp34. 执行过程5. 执行结

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

Java实现将HTML文件与字符串转换为图片

《Java实现将HTML文件与字符串转换为图片》在Java开发中,我们经常会遇到将HTML内容转换为图片的需求,本文小编就来和大家详细讲讲如何使用FreeSpire.DocforJava库来实现这一功... 目录前言核心实现:html 转图片完整代码场景 1:转换本地 HTML 文件为图片场景 2:转换 H

Java使用jar命令配置服务器端口的完整指南

《Java使用jar命令配置服务器端口的完整指南》本文将详细介绍如何使用java-jar命令启动应用,并重点讲解如何配置服务器端口,同时提供一个实用的Web工具来简化这一过程,希望对大家有所帮助... 目录1. Java Jar文件简介1.1 什么是Jar文件1.2 创建可执行Jar文件2. 使用java

SpringBoot实现不同接口指定上传文件大小的具体步骤

《SpringBoot实现不同接口指定上传文件大小的具体步骤》:本文主要介绍在SpringBoot中通过自定义注解、AOP拦截和配置文件实现不同接口上传文件大小限制的方法,强调需设置全局阈值远大于... 目录一  springboot实现不同接口指定文件大小1.1 思路说明1.2 工程启动说明二 具体实施2