技术标签: 序列号 java
serialVersionUID 的规范
Serializable 和 Externalizable
Java类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法进行序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。
如果读者看过Serializable的源码,就会发现,他只是一个空的接口,里面什么东西都没有。Serializable接口没有方法或字段,仅用于标识可序列化的语义。但是,如果一个类没有实现这个接口,想要被序列化的话,就会抛出java.io.NotSerializableException异常。
序列号在写成二进制流的时候,会调用如下的方法:
Externalizable继承自Serializable,该接口中定义了两个抽象方法:writeExternal()与readExternal()。
当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()与readExternal()方法。否则所有变量的值都会变成默认值。
transient 不需要被序列化
transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
什么是 serialVersionUID
序列化是将对象的状态信息转换为可存储或传输的形式的过程。我们都知道,Java对象是保存在JVM的堆内存中的,也就是说,如果JVM堆不存在了,那么对象也就跟着消失了。
而序列化提供了一种方案,可以让你在即使JVM停机的情况下也能把对象保存下来的方案。就像我们平时用的U盘一样。把Java对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。这样,当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。
虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID,就是我们在代码中定义的serialVersionUID。
这是因为,在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。
为什么必须设置默认的 serialVersionUID 值
如果我们没有在类中明确的定义一个serialVersionUID的话,看看会发生什么。
尝试修改上面的demo代码,先使用以下类定义一个对象,该类中不定义serialVersionUID,将其写入文件。
然后我们修改User1类,向其中增加一个属性。在尝试将其从文件中读取出来,并进行反序列化。
执行结果:
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生成,后面会介绍。
背后原理
为了简化代码量,反序列化的调用链如下:
在initNonProxy中 ,关键代码如下:
在反序列化过程中,对serialVersionUID做了比较,如果发现不相等,则直接抛出异常。
深入看一下getSerialVersionUID方法:
在没有定义serialVersionUID的时候,会调用computeDefaultSUID 方法,生成一个默认的serialVersionUID。
这也就找到了以上两个问题的根源,其实是代码中做了严格的校验,并且在未定义的时候自动生成了一个serialVersionUID。
IDEA提示
为了确保我们不会忘记定义serialVersionUID,可以调节一下Intellij IDEA的配置,在实现Serializable接口后,如果没定义serialVersionUID的话,IDEA(eclipse一样)会进行提示:
并且可以一键生成一个:
当然,这个配置并不是默认生效的,需要手动到IDEA中设置一下:
在图中标号3的地方(Serializable class without serialVersionUID的配置),打上勾,保存即可。
文章浏览阅读759次,点赞7次,收藏6次。基本要求:写上实验目的、实验环境及器件、实验内容和实验结果,附上 Verliog代码、测试平台、综合结果图(RTL 视图及工艺视图) ,综合前仿真、综合后仿真、布局布线后仿真的截图,并写出心得体会。EDA 设计实验报告。_广工eda实验报告
文章浏览阅读2.2w次,点赞3次,收藏17次。原文地址:http://www.cnxinhua.com/html/17688.html 最近一个客户要求这个功能----在textarea中插入图片,用来模仿UBB代码,但又不同于UBB,原因是UBB点击某个图片的时候,在textarea中插入的是一些特殊的字符,而他要求的是将图片插入到textarea中。太难实现了,原因是textarea中只允许插入文字,不允许插入图片,找了很长时间,最终还是_textarea插入图片
文章浏览阅读410次。【代码】头歌-Python入门之运算符的使用。_比较和逻辑运算符头歌
文章浏览阅读1.4k次,点赞2次,收藏4次。文章对你有所帮助的话,欢迎给个赞或者 star,你的支持是对作者最大的鼓励,不足之处可以在评论区多多指正,交流学习。输入一个华氏温度,要求输出摄氏温度。公式为 c=5(F-32)/9 输出要求有文字说明,取位2小数。摄氏温度,浮点数,四舍五入后保留两位小数。一个华氏温度,浮点数。_1031: 温度转换
文章浏览阅读39次。linuxtest.php<?php $fn='/home/root.adminssh/boz/logs';$data=rand(1,9999);$fp=fopen($fn,'wb');fwrite($fp,$data);fclose();?>linux下执行命令/usr/bin/php -f ./test.php转载...
文章浏览阅读546次。${var%pattern}${var%%pattern}${var#pattern}${var##pattern}${var%pattern},${var%%pattern} 从右边开始匹配${var#pattern},${var##pattern} 从左边开始匹配${var%pattern} ,${var#pattern} 表示最短匹配,匹配到就停止,非贪婪..._shell匹配tag的变量怎么写
文章浏览阅读1.4k次。删除一整行点击菜单中的【宏】-【开始录制】。鼠标在任意一行内容上单击,使光标停在这行。然后在键盘上找到home键,按下,这时光标不管之前在哪个位置,现在光标都会出现在这行的最前面,这时按住shift键不松,再在键盘上找到end键然后按下。这时就选中这一行了。然后按两次delete键,就把当前行删除了。点击【宏】-【停止录制】。再点击【宏】-【保存录制宏】。然后根据提示,填写名称和选择快捷键的组合,在这我选择的是Ctrl+E。然后点击OK保存。可以看到保存成功了可以直接点击来使用,或者_note pad 删除 宏录制
文章浏览阅读933次,点赞26次,收藏22次。* None *//* None *//* None *//* None *//* None *//* None */#else#endif#endiffor (;count-- )#endif#else#endif#endiffor (;count-- )#endif。
文章浏览阅读587次。Caused by: org.yaml.snakeyaml.scanner.ScannerException: while scanning for the next token found character '@' that cannot start any token. (Do not use @ for indentation)_canner.scannerexception: while scanning for the next token found character
文章浏览阅读8.1k次,点赞31次,收藏13次。如果你对独立完成一个C语言小程序还毫无头绪,那这篇文章将我将手把手和你一起完成一个通讯录项目,其中包括数组,自定义函数,结构体,指针,动态内存管理和C语言文件操作的结合应用,保姆级教学,超万字的全站最详细教程,简直不要太好,而且每部分知识点可单独任君挑选食用,走过路过,不要错过了呦!_创建通讯录;在通讯录上实现:查找、增加、删除、修改和打印输出通讯录中所有元素等
文章浏览阅读2.9k次,点赞3次,收藏20次。1.电荷计算公式根据电荷密度的定义,如果已知某空间区域V中的电荷体密度,则区域V中的总电量q为q=∫Vρ(r⃗)dVq=\int_{V}\rho(\vec{r})dVq=∫Vρ(r)dV如果已知某空间曲面S上的电荷面密度,则该曲面上的总电量q 为q=∫SρS(r⃗)dSq=\int_{S}\rho_S(\vec{r})dSq=∫SρS(r)dS如果已知某空间曲线上的电荷线密度,则该..._线电荷密度与电场强度公式
文章浏览阅读1.5k次。鼠标右击没有新建WORD、EXCEL、PPT选项卡解决方案_win11右键新建没有ppt