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" ...
 
随机推荐
- PHP 防范xss攻击
			
XSS 全称为 Cross Site Scripting,用户在表单中有意或无意输入一些恶意字符,从而破坏页面的表现! 看看常见的恶意字符XSS 输入: 1.XSS 输入通常包含 JavaScript ...
 - asp.net页面间传值的几种方法
			
表单提交 传送页面代码 <html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server ...
 - Visual Studio Usage
			
Navigation Double click on UI element goes to its _click event. F12 – for method or variable, go to ...
 - .csproj文件的配置 IIS可以调试
			
<ProjectExtensions> <VisualStudio> <FlavorProperties GUID="{349c5851-65df-11da-9 ...
 - 机器学习技法-神经网络(NNet)
			
课程地址:https://class.coursera.org/ntumltwo-002 重要!重要!重要~ 一.神经网络(NNet)的动机 神经网络有很久的历史,由感知机(perceptron)模型 ...
 - Spark读取HDFS文件,文件格式为GB2312,转换为UTF-8
			
package iie.udps.example.operator.spark; import scala.Tuple2; import org.apache.hadoop.conf.Configur ...
 - 正则表达式中参数g、i、m的作用(share)
			
参数 g g 只影响于 exec.match 方法. 若不指定 g,则:每次调用 exec 都只返回第一个匹配:match 也是只返回第一个匹配. 若指定 g,则:每次调用 exec 都从上一个匹配之 ...
 - 装载:关于拉格朗日乘子法与KKT条件
			
作者:@wzyer 拉格朗日乘子法无疑是最优化理论中最重要的一个方法.但是现在网上并没有很好的完整介绍整个方法的文章.我这里尝试详细介绍一下这方面的有关问题,插入自己的一些理解,希望能够对大家有帮助. ...
 - Codeforces Round #365 (Div. 2) B 前缀和
			
B. Mishka and trip time limit per test 1 second memory limit per test 256 megabytes input standard i ...
 - 前后台Json的转换
			
jsp:JSON.stringify(params):params:表示数组 servlet:Store store = (Store) JSONObject.toBean(JSONObject.fr ...