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://www.mkyong.com/java-best-practices/understand-the-serialversionuid/

在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!

ps:使用jdk serialver命令可生成serialVersionUID ,留个问题SerialVersionUID磁盘又是怎么处理的呢?

Java serialVersionUID的更多相关文章

  1. Java serialVersionUID作用和生成

    序列化和反序列化Java是面向对象的语言,与其他语言进行交互(比如与前端js进行http通信),需要把对象转化成一种通用的格式比如json(前端显然不认识Java对象),从对象到json字符串的转换, ...

  2. [Java]serialVersionUID的作用

    简单来说,Java的序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的.在进行反序列化时,JVM会把传来的 字节流中的serialVersionUID与本地相应实体(类 ...

  3. 理解serialVersionUID是什么?有什么用?如何生成?

    如果您曾经实现过Serializable接口,则必须遇到此警告消息 The serializable class xxx does not declare a static final serialV ...

  4. HowToDoInJava Java 教程·翻译完成

    原文:HowToDoInJava 协议:CC BY-NC-SA 4.0 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远. ApacheCN 学习资源 目录 核心 Java 教程 什 ...

  5. 对象序列化与反序列化local class incompatible

    无论eclipse还是idea(默认关闭序列化提示,需手动打开),都可以自动生成相应的序列号,分为两类1L,XXXL. 当然如果不指定,系统也会自动生成,但是存在隐性风险 ,不同的编译器对同一个对象可 ...

  6. Spark案例分析

    一.需求:计算网页访问量前三名 import org.apache.spark.rdd.RDD import org.apache.spark.{SparkConf, SparkContext} /* ...

  7. Java中serialVersionUID的解释及两种生成方式的区别(转载)

    转载自:http://blog.csdn.net/xuanxiaochuan/article/details/25052057 serialVersionUID作用:        序列化时为了保持版 ...

  8. JAVA中SERIALVERSIONUID的解释

    serialVersionUID作用:        序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性.有两种生成方式:       一个是默认的1L,比如:private st ...

  9. Java基础--serialVersionUID

    Java基础--serialVersionUID serialVersionUID作用: 序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性.有两种生成方式: 一个是默认的1L,比 ...

随机推荐

  1. oracle修改登录认证方式

    通过配置sqlnet.ora文件,我们可以修改oracle登录认证方式. SQLNET.AUTHENTICATION_SERVICES=(NTS);基于操作系统的认证 SQLNET.AUTHENTIC ...

  2. Linux查看系统负载常用命令

    1.查看负载 uptime :: up day, :, user, load average: 0.00, 0.00, 0.00 在过去1分钟.5分钟.15分钟内平均进程数量 2.查看用户 w :: ...

  3. JS1-属性操作

    属性操作语法 读操作:获取.找到 元素.属性名 写操作:“添加”.替换.修改 元素.属性名 = 新的值 元素.innerHTML => 读取元素里面所有的html代码 元素.innerHTML ...

  4. WisDom.Net 框架设计(八) 持久层

    WisDom.Net ---持久层  1.什么是持久层        持久层负责最基础的功能支撑,为项目提供一个高层,统一,和并发的数据持久机制,提供了比如建立数据库连接,关闭数据库连接,执行sql语 ...

  5. DBNull与Null

    DBNull与Null的区别在于,DBNull代表该字段在数据库中根本不存在,Null代表该字段在数据库中没有值.

  6. android下面res目录

    1. 相关文件夹介绍      在Android项目文件夹里面,主要的资源文件是放在res文件夹里面的.assets文件夹是存放不进行编译加工的原生文件,即该文件夹里面的文件不会像xml,java文件 ...

  7. C#线程池基础

    池(Pool)是一个很常见的提高性能的方式.比如线程池连接池等,之所以有这些池是因 为线程和数据库连接的创建和关闭是一种比较昂贵的行为.对于这种昂贵的资源我们往往会考虑在一个池容器中放置一些资源,在用 ...

  8. 【Windows】Windows中的数据类型以及命名

    一.大写标示符 Windows中的很多标识符都是以两个或者三个大写字母作为前缀的,且其后紧跟一个下划线.这些标识符都是常量数值,前缀表明该常量的一般类别.如下 前缀 常量 CS(Class Style ...

  9. ca-bundle.crt to java truststore(e.g. trustStore.jks)

    1. download java keyutilhttps://java-keyutil.googlecode.com/files/keyutil-0.4.0.jar 2. run the follo ...

  10. TUXEDO管理命令总结

    tmboot  启动服务: 参数说明: -l  lmid 启动逻辑服务器名为lmcd服务器上的所有进程 -g grpname 启动GROUP名为grpname的所有进程 -i  srvid 启动SRV ...