关于serialVersionUID的说明

关于serialVersionUID的说明java

一、为何要使用serialVersionUID
   (1)对于实现了Serializable接口的类,能够将其序列化输出至磁盘文件中,同时会将其serialVersionUID输出到文件中。
   (2)而后有须要使用时,再从磁盘将对象内容及serialVersionUID读入内容中的某个对象。
   (3)将磁盘内容读入对象时,须要进行强制类型转换,如Person person = (Person)ois.readObject(); 
   (4) 此时,将对比从磁盘读入的Serializable与对象所属类(如Person)的Serializable,若两者一致,则转换成功。若两者不一致,则转换失败,并抛出InvalidClassException。
     若是没有为类指定serialVersionUID,则JVM会自动根据类的内容生成一个serialVersionUID,类中的任何变化均会致使serialVersionUID的变化,如新增一个空格。

所以,若一个类没有指定serialVersionUID,并且发生了变化,则读取磁盘中的对象时就会报错。算法

二、什么时候应该修改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.安全

三、如何建立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便可。
  对于第一种,须要了解哪些状况是可兼容的,哪些根本就不兼容。 
  在可兼容的前提下,能够保留旧版本号,若是不兼容,或者想让它不兼容,就手工递增版本号。
  1->2->3.....
  第二种方式,是根据类的结构产生的hash值。增减一个属性、方法等,均可能致使这个值产生变化。我想这种方式适用于这样的场景:

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

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

[Java] 纯文本查看 复制代码
?eclipse

/(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;this

}

} spa

[Java] 纯文本查看 复制代码
?.net

/(将对象序列化到一个文件)**/
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();

[Java] 纯文本查看 复制代码
?

/(经过如下方法能够正常的将文件中保存的对象还原到内存中)**/
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这个类中添加一个成员变量,以下:

[Java] 纯文本查看 复制代码
?

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!

文章摘自::https://blog.csdn.net/jediael...

相关文章
相关标签/搜索