[Java]serialVersionUID的作用
简单来说,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,类型为long的变量时,Java
序列化机制会根据编译的class(它通过类名,方法名等诸多因素经过计算而得,理论上是一一映射的关系,也就是唯一的)自动生成一个
serialVersionUID作序列化版本比较用,这种情况下,如果class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释,等
等),就算再编译多次,serialVersionUID也不会变化的.
如果我们不希望通过编译来强制划分软件版本,即实现序列化接口的实体能够兼容先前版本,未作更改的类,就需要显式地定义一个名为serialVersionUID,类型为long的变量,不修改这个变量值的序列化实体都可以相互进行串行化和反串行化。
如果你没有考虑到兼容性问题时,就把它关掉,不过有这个功能是好的,只要任何类别实现了Serializable这个接口的话,如果没有加入
serialVersionUID,Eclipse都会给你warning提示,这个serialVersionUID为了让该类别
Serializable向后兼容。
问题一:假设有A端和B端,如果2处的serialVersionUID不一致,会产生什么错误呢?
问题二:假设2处serialVersionUID一致,如果A端增加一个字段,B端不变,会是什么情况呢?
问题三:假设2处serialVersionUID一致,如果B段增加一个字段,A端不变,会是什么情况呢?
问题四:假设2处serialVersionUID一致,如果A端减少一个字段,B端不变,会是什么情况呢?
问题五:假设2处serialVersionUID一致,如果B端减少一个字段,A端不变,会是什么情况呢?
例子如下:写2个类,类名相同,字段相同,方法相同.放在不同的包里,来模仿A端和B端.
实体类:在本例中,在测试类SerialTest执行前代表A端,然后,在测试类DeserialTest执行前代表B端.
package com.test;
import java.io.Serializable; public class Serial implements Serializable{
/**
*
*/
private static final long serialVersionUID = 6977402643848374753L;
int id;
String name;
public Serial(int id, String name) {
this.id = id;
this.name = name;
}
public String toString() {
return "DATA: " + id + " " +name;
}
}
测试类,代表A端的序列化
package com.test.serializable; import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream; public class SerialTest { /** * @param args */
public static void main(String[] args) {
// TODO Auto-generated method stub
Serial serial1 = new Serial(1,"song");
System.out.println("Object Serial"+serial1);
try {
FileOutputStream fos = new FileOutputStream("serialTest.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(serial1);
oos.flush();
oos.close();
}
catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
测试类,代表B端的反序列化
package com.test.serializable;
import java.io.FileInputStream; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.ObjectInputStream;
public class DeserialTest {
/** * @param args */ public static void main(String[] args) {
// TODO Auto-generated method stub Serial serial2 ; try {
FileInputStream fis = new FileInputStream("serialTest.txt");
ObjectInputStream ois = new ObjectInputStream(fis); serial2 =
(Serial)ois.readObject(); ois.close(); System.out.println("Object
Deserial"+serial2); } catch (FileNotFoundException e) { // TODO
Auto-generated catch block e.printStackTrace(); } catch
(IOException e) { // TODO Auto-generated catch block
e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO
Auto-generated catch block e.printStackTrace(); } }
}
问题一:假设有A端和B端,如果2处的serialVersionUID不一致,会产生什么错误呢?
答案如下:
1)先执行测试类SerialTest,然后修改serialVersion值(或注释掉serialVersion并编译),再执行测试类DeserialTest,报错:
java.io.InvalidClassException: com.test.serializable.Serial; local
class incompatible: stream classdesc serialVersionUID = 1, local class
serialVersionUID = 11
2)A端和B端都没显示的写serialVersionUID,实体类没有改动(如果class文件(类名,方法明等)没有发生变化(增加空格,换行,增加注释,等等),).序列化,反序列化正常.
问题二:假设2处serialVersionUID一致,如果A端增加一个字段,B端不变,会是什么情况呢?
答案二: 序列化,反序列化正常,A端增加的字段丢失(被B端忽略).
问题五:假设2处serialVersionUID一致,如果B端减少一个字段,A端不变,会是什么情况呢?
答案:与问题二类似,序列化,反序列化正常,B端字段少于A端,A端多的字段值丢失(被B端忽略).
问题三:假设2处serialVersionUID一致,如果B段增加一个字段,A端不变,会是什么情况呢?
问题四:假设2处serialVersionUID一致,如果A端减少一个字段,B端不变,会是什么情况呢?(与问题三类似,四答案:序列化,反序列化正常,B端字段多余A端,B端多出的字段被赋予对应类型的默认值)
答案三: 序列化,反序列化正常,B端新增加的int字段被赋予了默认值0.
例子如下:
3)先执行SerialTest,然后在实体类增加一个字段age,再执行测试类DeserialTest.
package com.test.serializable;
import java.io.Serializable;
public class Serial implements Serializable {
/** * */ private static final long serialVersionUID = -2337937881709830076L;
/** * */ //private static final long serialVersionUID = 1L; int id;
String name; public Serial(int id, String name) {
this.id = id; this.name = name; }
public String toString() { return "DATA: " + id + " "
+name; } public int age ;//在B端增加一个新字段 }
相应的修改测试类DeserialTest,打印出age的值.
package com.test.serializable;
import java.io.FileInputStream; import java.io.FileNotFoundException;
import java.io.IOException; import java.io.ObjectInputStream;
public class DeserialTest {
/** * @param args */ public static void main(String[] args) {
// TODO Auto-generated method stub Serial serial2 ; try {
FileInputStream fis = new FileInputStream("serialTest.txt");
ObjectInputStream ois = new ObjectInputStream(fis); serial2 =
(Serial)ois.readObject(); ois.close(); System.out.println("Object
Deserial"+serial2+" age="+serial2.age); } catch (FileNotFoundException
e) { // TODO Auto-generated catch block e.printStackTrace(); }
catch (IOException e) { // TODO Auto-generated catch block
e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO
Auto-generated catch block e.printStackTrace(); } }
}
打印结果如下:
Object DeserialDATA: 1 song age=0
说明序列化,反序列化正常,B端新增加的int字段被赋予了默认值0.
上面的情况对增加/减少 字段/方法 都适用.
//但当serialVersionUID相同时,它就会将不一样的field以type的预设值Deserialize,可避开不兼容性问题。
[Java]serialVersionUID的作用的更多相关文章
- serialVersionUID, ObjectInputStream与ObjectOutputStream类,Serializable接口,serialVersionUID的作用和用法
ObjectInputStream与ObjectOutputStream类所读写的对象必须实现Serializable接口,对象中的transient和static类型成员变量不会被读取和写入 Ser ...
- serialVersionUID的作用 (zz)
serialVersionUID的作用 2011-05-12 16:04:19| 分类: java|举报|字号 订阅 在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘 ...
- serialVersionUID的作用以及设置方法(转)
声明:本篇文章是转载的 http://blog.csdn.net/kakaxi_77/article/details/8129070 http://snowlotus.iteye.com/blog/2 ...
- serialVersionUID的作用以及如何用idea自动生成实体类的serialVersionUID
转载:http://blog.csdn.net/liuzongl2012/article/details/45168585 serialVersionUID的作用: 通过判断实体类的serialVer ...
- java 接口的作用和好处
1.java 接口的作用 http://blog.csdn.net/hack_bug/article/details/7634737 2.一位Java大牛的回答 很多JAVA初级程序员对于接口存在的意 ...
- Java 动态代理作用是什么?
Java 动态代理作用是什么? 1 条评论 分享 默认排序按时间排序 19 个回答 133赞同反对,不会显示你的姓名 Intopass 程序员,近期沉迷于动漫ING 133 人赞同 ① 首先你 ...
- Java关键字及其作用
Java关键字及其作用 一. 关键字总览 访问控制 private protected public 类,方法和变量修饰符 abstract class extends fin ...
- Java 过滤器的作用
Servlet API 非常久曾经就已成为企业应用开发的基石,而 Servlet 过滤器则是对 J2EE 家族的相对较新的补充.在 J2EE 探索者 系列文章的最后一篇中,作者 Kyle Gabhar ...
- 【Java学习笔记之一】java关键字及作用
Java关键字及其作用 一. 总览: 访问控制 private protected public 类,方法和变量修饰符 abstract class extends final implements ...
随机推荐
- jquery选择器(可见对象,不可见对象) +判断,对象(逆序)
//可见对象: $("li:visible ") //可见对象下的 隐藏对象 $("li:visible [type='hidden']") //获得 可见 的 ...
- Navcat12 for mysq 激活工具
Navcat12 for mysq 激活 https://www.cnblogs.com/sunyangCoder/p/9060454.html
- 【Oracle】数据库热备
1. 创建脚本 注:脚本第三行中的DB_NAME,需要改为自己的数据库名(show parameter name;): oracle用户下新建目录:/home/oracle/DB_NAME/hot_b ...
- linux抓包命令-tcpdump命令详解
最近调试支付接口的时候,遇到了一个奇怪的问题:我按照支付接口文档,对接支付通道,当消费业务正常后,调试查余和冲正的时候,支付通道的对接技术告诉我,系统没有我们支付系统的请求报文,数据库和日志中都没有, ...
- JS 公鸡2文一只、母鸡1文一只、小鸡0.5文一只若一共有100文钱买100只鸡有多少种方法
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- bzoj 1296: [SCOI2009]粉刷匠 动态规划
Description windy有 N 条木板需要被粉刷. 每条木板被分为 M 个格子. 每个格子要被刷成红色或蓝色. windy每次粉刷,只能选择一条木板上一段连续的格子,然后涂上一种颜色. 每个 ...
- Java 分布式事务
0 引言 本文主要介绍java中分布式事务以及对应的解决方案. 1 分布式事务产生的原因 1.1 数据库分库分表 当数据库单表一年产生的数据超过1000W,那么就要考虑分库分表,具体分库分表的原理在此 ...
- 商品的CRUD操作
(1)新增商品:新增文档,建立索引 PUT /index/type/id{ "json数据"} PUT /ecommerce/product/1{ "name" ...
- sublimText3 快捷键大全(转)
Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本. Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数名等. ...
- 基于BootStrap,FortAweSome,Ajax的学生管理系统
一. 基于BootStrap,FortAweSome,Ajax的学生管理系统代码部分 1.students.html <1>html页面文件 <!DOCTYPE html> & ...