我的编程空间,编程开发者的网络收藏夹
学习永远不晚

SerialVersionUID有什么作用

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

SerialVersionUID有什么作用

本文小编为大家详细介绍“SerialVersionUID有什么作用”,内容详细,步骤清晰,细节处理妥当,希望这篇“SerialVersionUID有什么作用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

Serializable 和 Externalizable

Java类通过实现 java.io.Serializable  接口以启用其序列化功能。未实现此接口的类将无法进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。

如果读者看过Serializable的源码,就会发现,他只是一个空的接口,里面什么东西都没有。Serializable接口没有方法或字段,仅用于标识可序列化的语义。但是,如果一个类没有实现这个接口,想要被序列化的话,就会抛出java.io.NotSerializableException异常。

它是怎么保证只有实现了该接口的方法才能进行序列化与反序列化的呢?

原因是在执行序列化的过程中,会执行到以下代码:

SerialVersionUID有什么作用

在进行序列化操作时,会判断要被序列化的类是否是Enum、Array和Serializable类型,如果都不是则直接抛出NotSerializableException。

Java中还提供了Externalizable接口,也可以实现它来提供序列化能力。

Externalizable继承自Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。

当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。否则所有变量的值都会变成默认值。

transient

transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient  变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

自定义序列化策略

在序列化过程中,如果被序列化的类中定义了writeObject 和 readObject 方法,虚拟机会试图调用对象类里的 writeObject 和  readObject 方法,进行用户自定义的序列化和反序列化。

如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject方法以及  ObjectInputStream 的 defaultReadObject 方法。

用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。

所以,对于一些特殊字段需要定义序列化的策略的时候,可以考虑使用transient修饰,并自己重写writeObject 和 readObject  方法,如java.util.ArrayList中就有这样的实现。

以上,就是一些读者需要掌握和和序列化有关的知识。

我们随便找几个Java中实现了序列化接口的类,如String、Integer等,我们可以发现一个细节,那就是这些类除了实现了Serializable外,还定义了一个serialVersionUID

SerialVersionUID有什么作用

那么,到底什么是serialVersionUID呢?为什么要设置这样一个字段呢?

什么是serialVersionUID

序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。

而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID  是否一致,这个所谓的序列化ID,就是我们在代码中定义的serialVersionUID。

如果serialVersionUID变了会怎样

我们举个例子吧,看看如果serialVersionUID被修改了会发生什么?

SerialVersionUID有什么作用

我们先执行以上代码,把一个User1对象写入到文件中。然后我们修改一下User1类,把serialVersionUID的值改为2L。

SerialVersionUID有什么作用

然后执行以下代码,把文件中的对象反序列化出来:

SerialVersionUID有什么作用

执行结果如下:

java.io.InvalidClassException: com.hollis.User1; local class incompatible:  stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

可以发现,以上代码抛出了一个java.io.InvalidClassException,并且指出serialVersionUID不一致。

这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。

这也是《阿里巴巴Java开发手册》中规定,在兼容性升级中,在修改类的时候,不要修改serialVersionUID的原因。除非是完全不兼容的两个版本。所以,serialVersionUID其实是验证版本一致性的。

如果读者感兴趣,可以把各个版本的JDK代码都拿出来看一下,那些向下兼容的类的serialVersionUID是没有变化过的。比如String类的serialVersionUID一直都是-6849794470754667710L。

但是,作者认为,这个规范其实还可以再严格一些,那就是规定:

如果一个类实现了Serializable接口,就必须手动添加一个private static final long  serialVersionUID变量,并且设置初始值。

为什么要明确定一个serialVersionUID

如果我们没有在类中明确的定义一个serialVersionUID的话,看看会发生什么。

尝试修改上面的demo代码,先使用以下类定义一个对象,该类中不定义serialVersionUID,将其写入文件。

SerialVersionUID有什么作用

然后我们修改User1类,向其中增加一个属性。在尝试将其从文件中读取出来,并进行反序列化。

SerialVersionUID有什么作用

执行结果:

java.io.InvalidClassException: com.hollis.User1; local class incompatible: stream classdesc serialVersionUID = -2986778152837257883, local class serialVersionUID = 7961728318907695402

同样,抛出了InvalidClassException,并且指出两个serialVersionUID不同,分别是-2986778152837257883和7961728318907695402。

从这里可以看出,系统自己添加了一个serialVersionUID。

所以,一旦类实现了Serializable,就建议明确的定义一个serialVersionUID。不然在修改类的时候,就会发生异常。

serialVersionUID有两种显示的生成方式:

一种是默认的1L,比如:

private static final long serialVersionUID = 1L;

另外一种是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:

private static final long serialVersionUID = xxxxL;

后面这种方式,可以借助IDE生成,后面会介绍。

背后原理

知其然,要知其所以然,我们再来看看源码,分析一下为什么serialVersionUID改变的时候会抛异常?在没有明确定义的情况下,默认的serialVersionUID是怎么来的?

为了简化代码量,反序列化的调用链如下:

SerialVersionUID有什么作用

在initNonProxy中 ,关键代码如下:

SerialVersionUID有什么作用

在反序列化过程中,对serialVersionUID做了比较,如果发现不相等,则直接抛出异常。

深入看一下getSerialVersionUID方法:

SerialVersionUID有什么作用

在没有定义serialVersionUID的时候,会调用computeDefaultSUID  方法,生成一个默认的serialVersionUID。

这也就找到了以上两个问题的根源,其实是代码中做了严格的校验,并且在未定义的时候自动生成了一个serialVersionUID。

IDEA提示

为了确保我们不会忘记定义serialVersionUID,可以调节一下Intellij  IDEA的配置,在实现Serializable接口后,如果没定义serialVersionUID的话,IDEA(eclipse一样)会进行提示:

SerialVersionUID有什么作用

并且可以一键生成一个:

SerialVersionUID有什么作用

当然,这个配置并不是默认生效的,需要手动到IDEA中设置一下:

SerialVersionUID有什么作用

在图中标号3的地方(Serializable class without serialVersionUID的配置),打上勾,保存即可。

读到这里,这篇“SerialVersionUID有什么作用”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注编程网行业资讯频道。

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

SerialVersionUID有什么作用

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

SerialVersionUID有什么作用

本文小编为大家详细介绍“SerialVersionUID有什么作用”,内容详细,步骤清晰,细节处理妥当,希望这篇“SerialVersionUID有什么作用”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。Seria
2023-06-16

serialVersionUID有什么用

这期内容当中小编将会给大家带来有关serialVersionUID有什么用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。序列化是一种对象持久化的手段。普遍应用在网络传输、RMI等场景中。类通过实现 jav
2023-06-19

serialversionuid是什么及有什么作用

本篇内容主要讲解“serialversionuid是什么及有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“serialversionuid是什么及有什么作用”吧!serialversio
2023-07-02

什么是serialVersionUID

serialVersionUID是Java中的一个静态常量,用于标识序列化类的版本号。当一个类实现了Serializable接口,即可将其对象序列化为字节流保存在文件中或通过网络传输。在反序列化的过程中,JVM会根据序列化类的版本号来判断是
2023-09-09

serialVersionUID作用全面解析

serialVersionUID适用于Java的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相
2023-05-31

SEO有什么作用

这篇文章主要介绍了SEO有什么作用,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。  玩过英雄联盟的朋友都知道,辅助在整个游戏中有着很大的作用,一个好的辅助往往可以拯救一局游戏
2023-06-10

CCriticalSection 有什么作用

CCriticalSection 是 C++ 中的一个类,它的作用是为了保护临界区代码,防止多个线程同时访问临界区代码而造成数据竞争和不一致性。临界区是指在多线程编程中一段需要互斥访问的代码,例如对共享资源的读写操作。当多个线程同时访问临界
2023-09-27

Linq有什么作用

本篇内容主要讲解“Linq有什么作用”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Linq有什么作用”吧!学习Linq在我们的软件中,数据的重要性不可言喻,特别是象ERP,CRM等等这类商业应用
2023-06-17

php有什么作用

这篇文章主要讲解了“php有什么作用”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“php有什么作用”吧!php是一种开源的通用计算机脚本语言,尤其适用于网络开发并可嵌入HTML中使用;PHP
2023-06-21

vps有什么作用

本篇内容介绍了“vps有什么作用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!vps是什么?vps又称为虚拟专用服务器,是指利用虚拟服务器软
2023-06-07

index.html有什么作用

index.html是一个网站的主页文件,它的作用是作为网站的入口页面。当用户访问一个网站时,网站服务器会默认加载并显示index.html文件。index.html通常包含网站的基本结构和内容,包括标题、导航栏、主要内容等。通过修改ind
2023-09-21

python有什么作用

python 是一种功能强大的高级编程语言,广泛应用于:数据科学和机器学习web 开发自动化和脚本处理人工智能科学计算教育和研究Python 的强大功能Python 是一种功能强大且用途广泛的高级编程语言,凭借其易读性、可扩展性和高效性,
python有什么作用
2024-04-20

Mybatis有什么作用

这篇文章主要为大家展示了“Mybatis有什么作用”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“Mybatis有什么作用”这篇文章吧。Mybatis 是一个实现了数据持久化的 ORM 框架,简单
2023-06-02

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录