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 的作用 和 两种添加方式相关推荐

  1. 初始化一个java空数组_Java 数组的两种初始化方式

    一.数组 1.数组中存储元素的类型是统一的,每一个元素在内存中所占用的空间大小是相同的,知道数组的首元素的内存地址,要查找的元素只要知道下标,就可以快速的计算出偏移量,通过首元素内存地址加上偏移量,就 ...

  2. java匿名内部类_java中匿名内部类的两种实现方式

    使用匿名内部类课使代码更加简洁.紧凑,模块化程度更高.内部类能够访问外部内的一切成员变量和方法,包括私有的,而实现接口或继承类做不到.然而这个不是我说的重点,我说的很简单,就是匿名内部类的两种实现方式 ...

  3. 将java对象存储到redis数据库(两种实现方式)

    本文为转载内容,特此声明,如若侵权,请联系删除,原文地址:https://www.cnblogs.com/potentPrince/p/8668544.html redis主要存储类型最常用的五种数据 ...

  4. Java防止Xss注入json_XSS的两种攻击方式及五种防御方式

    XSS介绍 跨站脚本攻击指的是自己的网站运行了别的网站里面的代码 攻击原理是原本需要接受数据但是一段脚本放置在了数据中: 该攻击方式能做什么? 获取页面数据 获取Cookies 劫持前端逻辑 发送请求 ...

  5. java的login_Java中login的两种实现方式

    方式一:将VO的东西封装到Action里面 编写Action方法 package action; import com.opensymphony.xwork2.ActionSupport; publi ...

  6. Java序列化有什么作用

    Java序列化有什么作用 一.作用 二.为什么没有被序列化的对象,也能进行传输 三.序列化的方式 1.Serializable 接口 2.Externalizable 接口 一.作用 对java对象进 ...

  7. java 数组合并_拼接_详解Java合并数组的两种实现方式

    详解Java合并数组的两种实现方式 发布于 2020-7-27| 复制链接 摘记: 最近在写代码时遇到了需要合并两个数组的需求,突然发现以前没用过,于是研究了一下合并数组的方式,总结如下.1.Syst ...

  8. Java两种排序方式快慢比较

    2019独角兽企业重金招聘Python工程师标准>>> Java中List的排序方式有两种,现在我们测试下这两种排序方式的快慢吧,我们需要用到两个类, 一个是运行程序的Main类,另 ...

  9. java 同步方式 lock_java的两种同步方式, Synchronized与ReentrantLock的区别

    java在编写多线程程序时,为了保证线程安全,需要对数据同步,经常用到两种同步方式就是Synchronized和重入锁ReentrantLock. 相似点: 这两种同步方式有很多相似之处,它们都是加锁 ...

  10. Java多线程两种实现方式的对比

    Java多线程两种实现方式的对比 一种,直接继承Thread类 一种,实现Thread类的Runnable接口 两种方式的区别 比如,售票厅有四个窗口,可以发售某日某次列出的100张车票,此时,100 ...

最新文章

  1. one pragmatical sqlhelper
  2. html表格中添加修改和删除链接,jQuery实现为table表格动态添加或删除tr功能示例...
  3. mapreduce编程规范_大数据之MapReduce详解
  4. 容器的访问元素的成员函数(front,back,下标和at)返回的都是引用
  5. 如何手动运行ASP.NET 2.0 Development Server
  6. netbeans调试_从NetBeans运行和调试WildFly Swarm应用程序
  7. Sublime 的中文乱码问题
  8. 原型和原型链原型继承_原型还是不原型:这就是问题所在。
  9. (六)为时装设计生成训练和运行GAN
  10. linux 下 libpcap 简单使用
  11. Guava 相关文章
  12. 数学分析原理 定理 6.5
  13. 从0开始学习C#第二天
  14. Python程序发布(打包)及pyInstaller、cx_Freeze工具使用介绍
  15. unity利用帧动画制作特效
  16. ls基本用法-查看文件大小 k m g
  17. 无法获取链接服务器 (null) 的 OLE DB 访问接口 SQLNCLI10 的架构行集
  18. 【数据结构PTA 7-158-161】
  19. QCustomPlot画带数值标签的柱状图
  20. WebView 视频播放,全屏按钮显示不出来,全屏后不能播放视频

热门文章

  1. LINUX下载编译OpenH264
  2. 手机配置都赶上笔记本了
  3. JDK粗体绘制效果为何如此之差
  4. 前端协商缓存强缓存如何使用_强制缓存(200)和协商缓存(304)
  5. 鸿蒙系统是华容网格吗,鸿蒙上手机还在迟疑,国内对手却已悄然来到
  6. basic语言基础 chm_拒付论文装订费错失博士学位,C语言之父毕业论文丢失52年重见天日...
  7. java screenframe_一个关于JFrame的问题
  8. c++ opencv mat_OpenCV计算机视觉-Core组件(一)
  9. xp电脑多少位怎么看_怎么看电脑是32位还是64位
  10. pycharm添加python注释头_pycharm使用教程——py文件自动添加文件头注释