详解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

相关文章

Python列表去重的4种核心方法与实战指南详解

《Python列表去重的4种核心方法与实战指南详解》在Python开发中,处理列表数据时经常需要去除重复元素,本文将详细介绍4种最实用的列表去重方法,有需要的小伙伴可以根据自己的需要进行选择... 目录方法1:集合(set)去重法(最快速)方法2:顺序遍历法(保持顺序)方法3:副本删除法(原地修改)方法4:

Spring Boot循环依赖原理、解决方案与最佳实践(全解析)

《SpringBoot循环依赖原理、解决方案与最佳实践(全解析)》循环依赖指两个或多个Bean相互直接或间接引用,形成闭环依赖关系,:本文主要介绍SpringBoot循环依赖原理、解决方案与最... 目录一、循环依赖的本质与危害1.1 什么是循环依赖?1.2 核心危害二、Spring的三级缓存机制2.1 三

在Spring Boot中浅尝内存泄漏的实战记录

《在SpringBoot中浅尝内存泄漏的实战记录》本文给大家分享在SpringBoot中浅尝内存泄漏的实战记录,结合实例代码给大家介绍的非常详细,感兴趣的朋友一起看看吧... 目录使用静态集合持有对象引用,阻止GC回收关键点:可执行代码:验证:1,运行程序(启动时添加JVM参数限制堆大小):2,访问 htt

SpringBoot集成Milvus实现数据增删改查功能

《SpringBoot集成Milvus实现数据增删改查功能》milvus支持的语言比较多,支持python,Java,Go,node等开发语言,本文主要介绍如何使用Java语言,采用springboo... 目录1、Milvus基本概念2、添加maven依赖3、配置yml文件4、创建MilvusClient

浅析Java中如何优雅地处理null值

《浅析Java中如何优雅地处理null值》这篇文章主要为大家详细介绍了如何结合Lambda表达式和Optional,让Java更优雅地处理null值,感兴趣的小伙伴可以跟随小编一起学习一下... 目录场景 1:不为 null 则执行场景 2:不为 null 则返回,为 null 则返回特定值或抛出异常场景

python logging模块详解及其日志定时清理方式

《pythonlogging模块详解及其日志定时清理方式》:本文主要介绍pythonlogging模块详解及其日志定时清理方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录python logging模块及日志定时清理1.创建logger对象2.logging.basicCo

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

Node.js 数据库 CRUD 项目示例详解(完美解决方案)

《Node.js数据库CRUD项目示例详解(完美解决方案)》:本文主要介绍Node.js数据库CRUD项目示例详解(完美解决方案),本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考... 目录项目结构1. 初始化项目2. 配置数据库连接 (config/db.js)3. 创建模型 (models/

SQL表间关联查询实例详解

《SQL表间关联查询实例详解》本文主要讲解SQL语句中常用的表间关联查询方式,包括:左连接(leftjoin)、右连接(rightjoin)、全连接(fulljoin)、内连接(innerjoin)、... 目录简介样例准备左外连接右外连接全外连接内连接交叉连接自然连接简介本文主要讲解SQL语句中常用的表

SpringMVC获取请求参数的方法

《SpringMVC获取请求参数的方法》:本文主要介绍SpringMVC获取请求参数的方法,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下... 目录1、通过ServletAPI获取2、通过控制器方法的形参获取请求参数3、@RequestParam4、@