为什么java中序列化的serialVersionUID总是无意义的?

简介: 这个题目不主要讲serialVersionUID作用,而是讲后面的那一串数字的意义,当然也会对java的这个serialVersionUID的作用进行一个讲解。这篇文章是我积压了很久的一篇文章,写了一半,几个月了才发现,于是拿出来好好整理一下。

一、serialVersionUID的作用


通过java进行网络之间的数据传输是不能直接把对象进行传的,需要在发送端把数据切分,在接收端对切分的数据进行重装。这种切分和重装的方式就叫做序列化。下面我们举一个例子:


(1)不指定serialVersionUID


首先我们定义一个User类,继承Serializable接口

v2-beeb617cf179e12bf6cd0dc010b1fa71_1440w.jpg

然后序列化

v2-eee891eab322f2f838c139bfdbc1da9d_1440w.jpg

反序列化

v2-07ab3a07b994517ac46401c66904c6ba_1440w.jpg

现在我们举了一个序列化的例子,没有指定serialVersionUID,此时程序在编译的时候就会自动为我们生成一个ID号,整个过程是这样的:


(1)发送端不指定serialVersionUID,编译器为我们默认生成,并序列化保存在流中发送到接收端。(2)接收端把serialVersionUID保存起来,进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化。也就是说传过来的ID和本地ID不一致时候就会出现错误。


现在验证一下第二种情况:

v2-20d6b39749c5d14a15940a712c038bae_1440w.jpg

我们再去反序列化的时候,因为JVM会把传来的字节流中的serialVersionUID与本地相应实体的serialVersionUID进行比较,发现不一致,因此会出现异常错误:

v2-655f8c5f661ee2a9617ec90ee70b9089_1440w.jpg

(2)指定serialVersionUID


这个情况就不展示了,不断你之前添加了多少个字段,或者进行更改,因为serialVersionUID唯一,因此反序列化都不会出现错误。

OK,这就是java中这个serialVersionUID的作用,其实就是给这个类添加一个身份ID,进行在序列化之前和之后进行版本的比对。 上面这个其实也是一个面试常问的一个问题,再次凑巧给总结了一下,不过今天的主题不是讲这个serialVersionUID的,而是后面的那一串数字为什么总是无意义的?


二、为什么总是无意义的ID?


java序列化中的serialVersionUID后面我们通常是1L、或者是xxxL。这些数字有什么意义呢?为什么我们总是需要这些无意义的ID。带着这些问题我们一步一步来揭晓答案。


1、有意义的ID


有一些ID是有意义的,最常见的就是我们的身份证号,一共18位。分别代表着省市县等等。在通常情况下这个ID在全国内是惟一的。他就像是一个标识符一样,唯一地代表了我们。


标识符(identifier)就是一个可以唯一识别一个对象或者物体的名称,被识别的对象可能是一些想法、物理上可数的对象或者物理上的不可数物质。它的前缀 ID 经常被用来表示身份、鉴定过程或者标识符。


因此唯一性是ID的最大特点。好比是我们的身份证号码,整个中国你找不出第二个和你一样号码的人。现在我们知道了有意义的ID通常情况下是一个标识符,唯一地代表了这个物体。现在我们把目光转到无意义的ID。


2、无意义的ID


我们的java序列化id、数据库中的自增主键、消息队列、甚至于我们的TCP通信中都会使用到这个。无意义的真正含义其实是和我们要做的事无关,也就是说这个ID数字不应该和我们的业务逻辑产生联系。


大多数业务的主键都会使用整数,它的上限一般就是 2^64,如果这些位数都用来表示记录的 ID,那么在有生之年基本上是不可能被使用完的,但是一旦我们将业务信息加入 ID,就会让原本无意义的 ID 变得有意义从而影响它的唯一性。


java序列化的那个例子,你看到serialVersionUID==xxxL,应该想不到这一串数字和这个类有什么联系吧。而且一旦有联系就有可能会出现错误。那为什么无意义的ID是有用的呢?我们举一个例子:在分布式系统中有一个分布式的 ID 生成器,Snowflake 算法会为 64 个比特的整数赋予不同的信息:


v2-d97a7bb4dc9f2a84d178deac66a2d88c_1440w.jpg

假设一台机器上一个时间单位最多只能生成 4096 个 ID,一旦超过了这个这个数量就有可能导致 ID 冲突或者乱序,从而失去其唯一性;这个算法中涉及的时间戳、数据中心标识符、机器标识符都没有办法解决唯一性的问题,哪怕这三者完全相等,此时仍然需要使用无其他意义的序列号来保证 ID 的唯一。


因此使用无意义 ID 的主要目的就是利用它的唯一性保证对象的标识符不会发生冲突,无意义 ID 的唯一作用就是保证唯一性,这能帮助我们避免业务字段可能存在潜在冲突的可能,这也提示我们想要使用联合字段构成主键时一定要深思熟虑。


3、总结


上面其实说了这么多,是想让各位有个稍微全面的了解。就像很多时候一句话讲完的事,非要BB半天。几句话总结:


对于有意义的ID,在特定场景下ID数字和业务逻辑有关,比如身份证号和每个人的唯一标识有关。


对于无意义的ID:这个ID数子一旦和业务逻辑产生联系,就有重复的可能,而且极其不安全。此时一个无意义的ID就有了唯一性。


不管有没有意义都是为了进行唯一标识,但是使用的场景不相同。


OK,今天的文章先写到这。

相关文章
|
3天前
|
存储 Java 数据库
|
3天前
|
存储 算法 Java
从零开始学习 Java:简单易懂的入门指南之IO序列化、打印流、压缩流(三十三)
从零开始学习 Java:简单易懂的入门指南之IO序列化、打印流、压缩流(三十三)
|
3天前
|
存储 安全 Java
Java一分钟之-Java序列化与反序列化
【5月更文挑战第14天】Java序列化用于将对象转换为字节流,便于存储和网络传输。实现`Serializable`接口使类可被序列化,但可能引发隐私泄露、版本兼容性和性能问题。要避免这些问题,可使用`transient`关键字、控制`serialVersionUID`及考虑使用安全的序列化库。示例代码展示了如何序列化和反序列化对象,强调了循环引用和未实现`Serializable`的错误。理解并妥善处理这些要点对优化代码至关重要。
14 1
|
3天前
|
分布式计算 Java 大数据
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
IO流【Java对象的序列化和反序列化、File类在IO中的作用、装饰器模式构建IO流体系、Apache commons-io工具包的使用】(四)-全面详解(学习总结---从入门到深化)
55 0
|
3天前
|
存储 Java 测试技术
滚雪球学Java(22):序列化和反序列化
【4月更文挑战第11天】🏆本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
33 1
滚雪球学Java(22):序列化和反序列化
|
3天前
|
SQL 存储 安全
每日一道面试题:Java中序列化与反序列化
每日一道面试题:Java中序列化与反序列化
13 0
|
3天前
|
存储 Java
Java输入输出:解释一下序列化和反序列化。
Java中的序列化和反序列化是将对象转换为字节流和反之的过程。ObjectOutputStream用于序列化,ObjectInputStream则用于反序列化。示例展示了如何创建一个实现Serializable接口的Person类,并将其序列化到文件,然后从文件反序列化回Person对象。
28 5
|
3天前
|
存储 Java Maven
java序列化
java序列化
|
3天前
|
存储 Java 数据库
序列化的 serialVersionUID 到底有什么用?
序列化的 serialVersionUID 到底有什么用?
29 3
|
3天前
|
存储 缓存 JSON
什么是Java序列化,它有哪些重要性
什么是Java序列化,它有哪些重要性