java 序列化 serialVersionUID 的作用 和 两种添加方式
serialVersionUID适用于Java的序列化机制。简单来说,Java的序列化机制是通过判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常,即是InvalidCastException。
serialVersionUID有两种显示的生成方式:
一是默认的1L,比如:private static final long serialVersionUID = 1L;
二是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段,比如:
private static final long serialVersionUID = xxxxL;
当一个类实现了Serializable接口,如果没有显示的定义serialVersionUID,Eclipse会提供相应的提醒。面对这种情况,我们只需要在Eclipse中点击类中warning图标一下,Eclipse就会 自动给定两种生成的方式。如果不想定义,在Eclipse的设置中也可以把它关掉的,设置如下:
Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems
将Serializable class without serialVersionUID的warning改成ignore即可。
当实现java.io.Serializable接口的类没有显式地定义一个serialVersionUID变量时候,Java序列化机制会根据编译的Class自动生成一个serialVersionUID作序列化版本比较用,这种情况下,如果Class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释等等),就算再编译多次,serialVersionUID也不会变化的。
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。
下面用代码说明一下serialVersionUID在应用中常见的几种情况。
(1)序列化实体类
1 import java.io.Serializable; 2 public class Person implements Serializable 3 { 4 private static final long serialVersionUID = 1234567890L; 5 public int id; 6 public String name; 7 8 public Person(int id, String name) 9 { 10 this.id = id; 11 this.name = name; 12 } 13 14 public String toString() 15 { 16 return "Person: " + id + " " + name; 17 } 18 }
(2)序列化功能:
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.ObjectOutputStream; 4 5 public class SerialTest 6 { 7 8 public static void main(String[] args) throws IOException 9 { 10 Person person = new Person(1234, "wang"); 11 System.out.println("Person Serial" + person); 12 FileOutputStream fos = new FileOutputStream("Person.txt"); 13 ObjectOutputStream oos = new ObjectOutputStream(fos); 14 oos.writeObject(person); 15 oos.flush(); 16 oos.close(); 17 } 18 }
(3)反序列化功能:
1 import java.io.FileInputStream; 2 import java.io.IOException; 3 import java.io.ObjectInputStream; 4 public class DeserialTest 5 { 6 public static void main(String[] args) throws IOException, ClassNotFoundException 7 { 8 Person person; 9 10 FileInputStream fis = new FileInputStream("Person.txt"); 11 ObjectInputStream ois = new ObjectInputStream(fis); 12 person = (Person) ois.readObject(); 13 ois.close(); 14 System.out.println("Person Deserial" + person); 15 } 16 17 }
情况一:假设Person类序列化之后,从A端传输到B端,然后在B端进行反序列化。在序列化Person和反序列化Person的时候,A端和B端都需要存在一个相同的类。如果两处的serialVersionUID不一致,会产生什么错误呢?
【答案】可以利用上面的代码做个试验来验证:
先执行测试类SerialTest,生成序列化文件,代表A端序列化后的文件,然后修改serialVersion值,再执行测试类DeserialTest,代表B端使用不同serialVersion的类去反序列化,结果报错:
Exception in thread "main" java.io.InvalidClassException: test.Person; local class incompatible: stream classdesc serialVersionUID = 1234567890, local class serialVersionUID = 123456789at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:560)at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1580)at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1493)at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1729)at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1326)at java.io.ObjectInputStream.readObject(ObjectInputStream.java:348)at test.DeserialTest.main(DeserialTest.java:15)
情况二:假设两处serialVersionUID一致,如果A端增加一个字段,然后序列化,而B端不变,然后反序列化,会是什么情况呢?
【答案】新增 public int age; 执行SerialTest,生成序列化文件,代表A端。删除 public int age,反序列化,代表B端,最后的结果为:执行序列化,反序列化正常,但是A端增加的字段丢失(被B端忽略)。
情况三:假设两处serialVersionUID一致,如果B端减少一个字段,A端不变,会是什么情况呢?
【答案】序列化,反序列化正常,B端字段少于A端,A端多的字段值丢失(被B端忽略)。
情况四:假设两处serialVersionUID一致,如果B端增加一个字段,A端不变,会是什么情况呢?
验证过程如下:
先执行SerialTest,然后在实体类Person增加一个字段age,如下所示,再执行测试类DeserialTest.
1 import java.io.Serializable; 2 public class Person implements Serializable 3 { 4 private static final long serialVersionUID = 123456789L; 5 public int id; 6 public String name; 7 public int age; 8 9 public Person(int id, String name) 10 { 11 this.id = id; 12 this.name = name; 13 } 14 15 public String toString() 16 { 17 return "Person: " + id + " " + name; 18 } 19 }
相应的修改测试类DeserialTest,打印出age的值。
1 import java.io.FileOutputStream; 2 import java.io.IOException; 3 import java.io.ObjectOutputStream; 4 5 public class SerialTest 6 { 7 8 public static void main(String[] args) throws IOException 9 { 10 Person person = new Person(1234, "wang"); 11 System.out.println("Person Serial" + person + " age:" + person.age); 12 FileOutputStream fos = new FileOutputStream("Person.txt"); 13 ObjectOutputStream oos = new ObjectOutputStream(fos); 14 oos.writeObject(person); 15 oos.flush(); 16 oos.close(); 17 } 18 }
结果为:
Person Deserial Person: 1234 wang age: 0
说明序列化,反序列化正常,B端新增加的int字段被赋予了默认值0。
最后通过下面的图片,总结一下上面的几种情况。
原文:http://swiftlet.net/archives/1268
转载于:https://www.cnblogs.com/loveincode/p/7413215.html
java 序列化 serialVersionUID 的作用 和 两种添加方式相关推荐
- 初始化一个java空数组_Java 数组的两种初始化方式
一.数组 1.数组中存储元素的类型是统一的,每一个元素在内存中所占用的空间大小是相同的,知道数组的首元素的内存地址,要查找的元素只要知道下标,就可以快速的计算出偏移量,通过首元素内存地址加上偏移量,就 ...
- java匿名内部类_java中匿名内部类的两种实现方式
使用匿名内部类课使代码更加简洁.紧凑,模块化程度更高.内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到.然而这个不是我说的重点,我说的很简单,就是匿名内部类的两种实现方式 ...
- 将java对象存储到redis数据库(两种实现方式)
本文为转载内容,特此声明,如若侵权,请联系删除,原文地址:https://www.cnblogs.com/potentPrince/p/8668544.html redis主要存储类型最常用的五种数据 ...
- Java防止Xss注入json_XSS的两种攻击方式及五种防御方式
XSS介绍 跨站脚本攻击指的是自己的网站运行了别的网站里面的代码 攻击原理是原本需要接受数据但是一段脚本放置在了数据中: 该攻击方式能做什么? 获取页面数据 获取Cookies 劫持前端逻辑 发送请求 ...
- java的login_Java中login的两种实现方式
方式一:将VO的东西封装到Action里面 编写Action方法 package action; import com.opensymphony.xwork2.ActionSupport; publi ...
- Java序列化有什么作用
Java序列化有什么作用 一.作用 二.为什么没有被序列化的对象,也能进行传输 三.序列化的方式 1.Serializable 接口 2.Externalizable 接口 一.作用 对java对象进 ...
- java 数组合并_拼接_详解Java合并数组的两种实现方式
详解Java合并数组的两种实现方式 发布于 2020-7-27| 复制链接 摘记: 最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下.1.Syst ...
- Java两种排序方式快慢比较
2019独角兽企业重金招聘Python工程师标准>>> Java中List的排序方式有两种,现在我们测试下这两种排序方式的快慢吧,我们需要用到两个类, 一个是运行程序的Main类,另 ...
- java 同步方式 lock_java的两种同步方式, Synchronized与ReentrantLock的区别
java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock. 相似点: 这两种同步方式有很多相似之处,它们都是加锁 ...
- Java多线程两种实现方式的对比
Java多线程两种实现方式的对比 一种,直接继承Thread类 一种,实现Thread类的Runnable接口 两种方式的区别 比如,售票厅有四个窗口,可以发售某日某次列出的100张车票,此时,100 ...
最新文章
- one pragmatical sqlhelper
- html表格中添加修改和删除链接,jQuery实现为table表格动态添加或删除tr功能示例...
- mapreduce编程规范_大数据之MapReduce详解
- 容器的访问元素的成员函数(front,back,下标和at)返回的都是引用
- 如何手动运行ASP.NET 2.0 Development Server
- netbeans调试_从NetBeans运行和调试WildFly Swarm应用程序
- Sublime 的中文乱码问题
- 原型和原型链原型继承_原型还是不原型:这就是问题所在。
- (六)为时装设计生成训练和运行GAN
- linux 下 libpcap 简单使用
- Guava 相关文章
- 数学分析原理 定理 6.5
- 从0开始学习C#第二天
- Python程序发布(打包)及pyInstaller、cx_Freeze工具使用介绍
- unity利用帧动画制作特效
- ls基本用法-查看文件大小 k m g
- 无法获取链接服务器 (null) 的 OLE DB 访问接口 SQLNCLI10 的架构行集
- 【数据结构PTA 7-158-161】
- QCustomPlot画带数值标签的柱状图
- WebView 视频播放,全屏按钮显示不出来,全屏后不能播放视频
热门文章
- LINUX下载编译OpenH264
- 手机配置都赶上笔记本了
- JDK粗体绘制效果为何如此之差
- 前端协商缓存强缓存如何使用_强制缓存(200)和协商缓存(304)
- 鸿蒙系统是华容网格吗,鸿蒙上手机还在迟疑,国内对手却已悄然来到
- basic语言基础 chm_拒付论文装订费错失博士学位,C语言之父毕业论文丢失52年重见天日...
- java screenframe_一个关于JFrame的问题
- c++ opencv mat_OpenCV计算机视觉-Core组件(一)
- xp电脑多少位怎么看_怎么看电脑是32位还是64位
- pycharm添加python注释头_pycharm使用教程——py文件自动添加文件头注释