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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.io.Serializable;
public class Person implements Serializable
{
private static final long serialVersionUID = 1234567890L;
public int id;
public String name;
public Person(int id, String name)
{
this.id = id;
this.name = name;
}
public String toString()
{
return "Person: " + id + " " + name;
}
}
|
(2)序列化功能:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerialTest
{
public static void main(String[] args) throws IOException
{
Person person = new Person(1234, "wang");
System.out.println("Person Serial" + person);
FileOutputStream fos = new FileOutputStream("Person.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.flush();
oos.close();
}
}
|
(3)反序列化功能:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeserialTest
{
public static void main(String[] args) throws IOException, ClassNotFoundException
{
Person person;
FileInputStream fis = new FileInputStream("Person.txt");
ObjectInputStream ois = new ObjectInputStream(fis);
person = (Person) ois.readObject();
ois.close();
System.out.println("Person Deserial" + person);
}
}
|
情况一:假设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 = 123456789
at 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import java.io.Serializable;
public class Person implements Serializable
{
private static final long serialVersionUID = 123456789L;
public int id;
public String name;
public int age;
public Person(int id, String name)
{
this.id = id;
this.name = name;
}
public String toString()
{
return "Person: " + id + " " + name;
}
}
|
相应的修改测试类DeserialTest,打印出age的值。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerialTest
{
public static void main(String[] args) throws IOException
{
Person person = new Person(1234, "wang");
System.out.println("Person Serial" + person + " age:" + person.age);
FileOutputStream fos = new FileOutputStream("Person.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(person);
oos.flush();
oos.close();
}
}
|
结果为:
Person Deserial Person: 1234 wang age: 0
说明序列化,反序列化正常,B端新增加的int字段被赋予了默认值0。
最后通过下面的图片,总结一下上面的几种情况。
转自:http://swiftlet.net/archives/1268
思考疑问:不过serialVersionUID既然是版本控制用的,主要是为了兼容性,serialVersionUID都一致了的话兼容性就有保障,那么为什么还会有不一样的情况呢(也就是不写的时候默认 随着类结构变化,是会不一样的) ,可能是想告诉调用者,类的结构已经变化过了?但是这种场景基本没遇到过。
serialVersionUID 的用途--转加自己的疑问的更多相关文章
- perfectpixel 加载PSD图到网页中和已经写好的网页进行对比
perfectpixel 这是火狐的插件: 用途:加载设计图,和 已经编写好的网页进行对比,看是否完美还原. 谷歌也有类似的插件,但是无法下载.
- Java IO流
File类 ·java.io.File类:文件和目录路径名的抽象表示形式,与平台无关 ·File能新建.删除.重命名文件和目录,但File不能访问文件内容本身.如果需要访问文件内容本身,则需要使用输入 ...
- 第十一章 IO流
11.IO流 11.1 java.io.File类的使用 1课时 11.2 IO原理及流的分类 1课时 11.3 节点流(或文件流) 1课时 11.4 缓冲流 1课时 11.5 转换流 1课时 11. ...
- java io 好文传送
转自:白大虾 地址:https://www.cnblogs.com/baixl/p/4170599.html 主要内容 java.io.File类的使用 IO原理及流的分类 文件流 FileInput ...
- SpringMVC框架之第三篇
2.高级参数绑定(重点) 2.1.数组类型 数组类型的参数可以传递一批相同的数据到Controller的方法中. 2.1.1.需求 批量删除:在商品列表页面选中多个商品,然后删除. 2.1.2.需求分 ...
- OpenSSL和Python实现RSA Key公钥加密私钥解密
基于非对称算法的RSA Key主要有两个用途,数字签名和验证(私钥签名,公钥验证),以及非对称加解密(公钥加密,私钥解密).本文提供一个基于OpenSSL和Python进行非对称加解密的例子. 1. ...
- 记录分享公司Spring data相关配置
起因 公司Spring Data相关的配置还是有点意思的,不过蛮复杂的...XML很多...我不太喜欢强行记住....所以我打算记录一下配置的大致思路和结构,以后可能会有用.... 总体结构 总体结构 ...
- 项目组J2ee程序员的标志,你中招没 转载+评论
原文在此 校园级别的程序员的标志: 代码中最多的是嵌套if(null == xxx),还要告诉你,null必须写在前面,我靠. 防止把==写成=,c语言时代常犯的错误.由于null不能做左值,在写=的 ...
- Python PIL ImageDraw 和ImageFont模块学习
ImageDraw 新建一个空白图片为本文作示例,新建空白文件的方法 见Image模块,Image.new: import Image blank = Image.new("RGB" ...
随机推荐
- C#导入、导出功能
//导出功能 protected void btnExport(object sender, EventArgs e) { //用来打开下载窗口 string fileName = "中心联 ...
- 清除浮动2-父元素设置overflow:hidden
<!doctype html><html> <head> <meta charset="UTF-8"> <meta name= ...
- Smart210学习记录-------Linux设备驱动结构
cdev结构体 1 struct cdev { 2 struct kobject kobj; /* 内嵌的 kobject 对象 */ 3 struct module *owner; /*所属模块*/ ...
- 在magneto系统中输出tier price的最小值
2012年6月16日星期六 Asia/Shanghai上午11时39分22秒 有的时候,我们想输出产品的tier price 的最小值!如图: 下面是解决的办法: 1. 在catalog/produc ...
- 转:Web.config配置文件详解(新手必看)
转:http://www.cnblogs.com/gaoweipeng/archive/2009/05/17/1458762.html 花了点时间整理了一下ASP.NET Web.config配置文件 ...
- 《深入浅出Node.js》第3章 异步I/O
@by Ruth92(转载请注明出处) 第3章 异步I/O Node 的基调:异步 I/O.事件驱动.单线程. Node 不再是一个服务器,而是一个可以基于它构建各种高速.可伸缩网络应用的平台. No ...
- Azure 云助手正式发布
Azure云服务在中国市场风生水起,越来越多的用户选择Azure作为平台将业务转向云端.随着移动互联网在中国的蓬勃发展,手机应用的体验深入人们的生活及工作.用户管控云服务也不应该只局限于电脑前,而是可 ...
- (基础篇)PHP与Web页面交互
PHP与Web页面交互是实现PHP网站与用户交互的重要手段.在PHP中提供了两种与Web页面交互的方法,一种是通过Web表单提交数据,另一种是通过URL参数传递. 这里我们将详细讲解表单的相关知识,为 ...
- AC自动机 专题
// 求目标串中出现了几个模式串 //==================== #include <stdio.h> #include <algorithm> #include ...
- [翻译]深度学习的机器(The learning machines)
学习的机器 用大量的数据识别图像和语音,深度学习的计算机(deep-learning computers) 向真正意义上的人工智能迈出了一大步. Nicola Jones Computer Scien ...