1、为什么要使用serialVersionUID

(1)对于实现了Serializable接口的类,可以将其序列化输出至磁盘文件中,同时会将其serialVersionUID输出到文件中。

(2)然后有需要使用时,再从磁盘将对象内容及serialVersionUID读入内容中的某个对象。

(3)将磁盘内容读入对象时,需要进行强制类型转换,如Person person = (Person)ois.readObject();

(4) 此时,将对比从磁盘读入的Serializable与对象所属类(如Person)的Serializable,若二者一致,则转换成功。若二者不一致,则转换失败,并抛出InvalidClassException。

如果没有为类指定serialVersionUID,则JVM会自动根据类的内容生成一个serialVersionUID,类中的任何变化均会导致serialVersionUID的变化,如新增一个空格。

因此,若一个类没有指定serialVersionUID,而且发生了变化,则读取磁盘中的对象时就会报错。

2、何时应该修改serialVersionUID

若对象已经修改较多或者修改成不兼容的模式,导致原来输出到磁盘的内容不应再转换至原对象,此时则应该修改serialVersionUID。

When should update your serialVersionUID?

When your serialization class is updated with some incompatible Java type changes to a serializable class, you have to update
your serialVersionUID.

3、如何创建serialVersionUID

以下内容参考:http://zengxiankang2011.blog.163.com/blog/static/1783603192011594938588/?fromdm&isFromSearchEngine=yes

在Eclipse中,提供两种方式让我们快速添加SerialVersionUid。



add default serial version ID:

Adds a default serial version ID to the selected type

Use this option to add a user-defined ID in combination with custom serialization code if the type did undergo structural change since its first release.



add generated serial version ID:

Adds a generated serial version ID to the selected type

Use this option to add a compiler-generated ID if the type didnot undergo structural change since its first release.





一种就是1L,一种是生成一个很大的数,这两种有什么区别呢?



看上去,好像每个类的这个类不同,似乎这个SerialVersionUid在类之间有某种关联。其实不然,两种都可以,从JDK文档也看不出这一点。我们只要保证在同一个类中,不同版本根据兼容需要,是否更改SerialVersionUid即可。



对于第一种,需要了解哪些情况是可兼容的,哪些根本就不兼容。 参考文档:http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf



在可兼容的前提下,可以保留旧版本号,如果不兼容,或者想让它不兼容,就手工递增版本号。



1->2->3.....





第二种方式,是根据类的结构产生的hash值。增减一个属性、方法等,都可能导致这个值产生变化。我想这种方式适用于这样的场景:



开发者认为每次修改类后就需要生成新的版本号,不想向下兼容,操作就是删除原有serialVesionUid声明语句,再自动生成一下。

以下内容转自http://blog.csdn.net/jimforme/article/details/5120587

在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中,说白了,就是能将一个2进制文件变成内存中的对象。在JAVA中,要实现这种机制,只要实现Serializable接口就可以了,先看下面这个简单例子,serialVersionUID稍后引出。我们先定义一个简单的Person类,然后创建这个对象,最后序列化它到一个文件。

/*****(Person类)*******/
import java.io.Serializable;
public class Person implements Serializable {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

/*****(将对象序列化到一个文件)*******/

import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class WhySerialversionUID {
public static void main(String[] args) throws Exception {
Person person= new Person();
person.setName("jack");
ObjectOutputStream oo = new ObjectOutputStream (new FileOutputStream(new File("E://jack.test")));
oo.writeObject(person);
oo.close();

/*****(通过以下方法可以正常的将文件中保存的对象还原到内存中)*******/

import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream; public class WhySerialversionUID {
public static void main(String[] args) throws Exception {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File("E://jack.test")));
Person person = (Person)ois.readObject();
String name= person.getName();
System.Out.Print("name is: "+name);

一切都那么顺利,但是如果在序列化之后,Person这个类发生了改变呢?比如,多了一个成员变量。我们做如下试验,还是先将对象序列化到一个文件中,之后在Person这个类中添加一个成员变量,如下: 

import java.io.Serializable;
public class Person implements Serializable {
private String name;
//添加这么一个成员变量
private String address;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

之后,我们再去运行一下还原,就发现运行出错了,会报如下错误:

Exception in thread “main” java.io.InvalidClassException: Person; local class incompatible: stream classdesc serialVersionUID = 8383901821872620925, local class serialVersionUID = -763618247875550322

意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。之前,在我们的例子中,我们是没有指定serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,我们添加了一个字段后,由于没有显指定serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个号码不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法可以用,呵呵。但是serialVersionUID我们怎么去生成呢?你可以写1,也可以写2,都无所谓,但是最好还是按照摘要算法,生成一个惟一的指纹数字,eclipse可以自动生成的,jdk也自带了这个工具。一般写法类似于

private static final long serialVersionUID = -763618247875550322L;在引用serializable这个类的前面有一个感叹号,单击这个感叹号后会有提示,一个是默认的,一个为此类自动产生一个SerialVersionUID!


版权声明:本文为博主原创文章,未经博主允许不得转载。

关于serialVersionUID的说明 分类: B1_JAVA 2014-05-24 11:02 1334人阅读 评论(0) 收藏的更多相关文章

  1. 百度编辑器UEditor ASP.NET示例Demo 分类: ASP.NET 2015-01-12 11:18 346人阅读 评论(0) 收藏

    在百度编辑器示例代码基础上进行了修改,封装成类库,只需简单配置即可使用. 完整demo下载 版权声明:本文为博主原创文章,未经博主允许不得转载.

  2. 棋盘问题 分类: 搜索 POJ 2015-08-09 13:02 4人阅读 评论(0) 收藏

    棋盘问题 Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 28474 Accepted: 14084 Description 在一 ...

  3. 二分图匹配(KM算法)n^4 分类: ACM TYPE 2014-10-04 11:36 88人阅读 评论(0) 收藏

    #include <iostream> #include<cstring> #include<cstdio> #include<cmath> #incl ...

  4. Segment Tree with Lazy 分类: ACM TYPE 2014-08-29 11:28 134人阅读 评论(0) 收藏

    #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; stru ...

  5. 8大排序算法图文讲解 分类: Brush Mode 2014-08-18 11:49 78人阅读 评论(0) 收藏

    排序算法可以分为内部排序和外部排序,内部排序是数据记录在内存中进行排序,而外部排序是因排序的数据很大,一次不能容纳全部的排序记录,在排序过程中需要访问外存. 常见的内部排序算法有:插入排序.希尔排序. ...

  6. 指向函数的指针 分类: C/C++ 2015-07-13 11:03 14人阅读 评论(0) 收藏

    原文网址:http://www.cnblogs.com/zxl2431/archive/2011/03/25/1995285.html 讲的很清楚,备份记录. (一) 用函数指针变量调用函数 可以用指 ...

  7. iOS调用相机,相册,上传头像 分类: ios技术 2015-04-14 11:23 256人阅读 评论(0) 收藏

    一.新建工程 二.拖控件,创建映射 三.在.h中加入delegate @interface ViewController : UIViewController 复制代码 四.实现按钮事件 -(IBAc ...

  8. IOS即时通讯XMPP搭建openfire服务器 分类: ios技术 2015-03-07 11:30 53人阅读 评论(0) 收藏

    一.下载并安装openfire 1.到http://www.igniterealtime.org/downloads/index.jsp下载最新openfire for mac版 比如:Openfir ...

  9. UIAlertController高级之嵌入其他控件 分类: ios技术 2015-02-02 11:58 96人阅读 评论(0) 收藏

    在编码过程中,我们经常遇到需要这样一个效果,就是弹出框的嵌套; 举个最简单的例子,比如你要选择时间,必然需要一个时间选择器DatePicker.但是这个选择器又是在你点击某按钮时弹出,弹出方式最常见的 ...

随机推荐

  1. jquery表格简单插件

    1.一直对jquery插件感觉非常神奇.今天动手写了一个超级简单的案例. 2.效果 3.体会 a.jquery插件编写能力. 须要具备一定js能力的编写.还有写css样式的运用:希望以后这方面会有提高 ...

  2. 高性能计算机传奇(vamei)

    高性能计算机是用网络将多台计算机连接在一起.并构成一个统一的系统,从而拥有远超个人电脑的计算能力.这样利用网络,让计算机合作工作的并行系统又称为集群(cluster).server.分布式计算机.超级 ...

  3. js 限制只能输入数字小数点

    function checkNum(e) { var re = /^\d+(?=\.{0,1}\d+$|$)/ if (e.value != "") { if (!re.test( ...

  4. jmeter--FTP测试

    FTP服务主要提供上传和下载功能.有时间需要我们测试服务器上传和下载的性能.在这里我通过JMeter做一个FTP测试计划的例子. 当然,JMeter官方网站的用户手册也有例子,但由于版本较早,我也算是 ...

  5. 手把手教你用NDK9编译ffmpeg2.4.2

    编译环境: 32位 ubuntu12.10 android-ndk-r9c-linux-x86.tar.bz2 ffmpeg-2.4.2.tar.bz2 网上的教程都是以低版本号ffmpeg编译居多. ...

  6. dot 语法全介绍

    0. 保存 保存为 pdf:dot -Tpdf iris.dot -o iris.pdf 1. 基本 (1)无向图.有向图.子图 graph G {} // 无向图 digraph G {} // 有 ...

  7. 洛谷 P1727 计算π

    P1727 计算π 题目背景 <爱与愁的故事第二弹·compute>第一章. 题目描述 中秋至,博饼声铿锵不断.爱与愁大神兴致勃勃地到学校博饼,结果抱回家的只有一秀二举.爱与愁大神十分生气 ...

  8. 微信支付v2开发(5) 订单查询

    本文介绍微信支付中订单查询功能的实现. 作者:方倍工作室 地址:http://www.cnblogs.com/txw1958/p/wxpay-order-query.html 一.订单查询 因为某一方 ...

  9. (转)c运行库、c标准库、windows API的区别和联系

    C运行时库函数C运行时库函数是指C语言本身支持的一些基本函数,通常是汇编直接实现的.  API函数API函数是操作系统为方便用户设计应用程序而提供的实现特定功能的函数,API函数也是C语言的函数实现的 ...

  10. HibernateCRUD基础框架(1)-实体类

    HibernateCRUD基础框架包括3篇文章,主要讲述整个CRUD基础框架的思路. 第1篇:讲述最基本的实体类,这些实体类是对SQL语言中的一些概念的封装. 第2篇:在这些实体类的基础上,开发一个& ...