Java序列化

赵立华 2024-11-06 浏览次数:0

Java中serialVersionUID的解释及两种生成方式的区别

Java序列化

 在网络传输Java对象、将Java对象存储到文件、将Java对象以BLOB形式存储到数据库中时,需要对Java对象进行序列化及反序列化,标准模式是实现Serializable接口。     实现上述接口时,需要提供一个Serial Version UID,该UID用于标识类的版本。一个对象被序列化后,只要其版本不变,都可以进行反序列化,一旦  改变造成版本不一致,会抛出InvalidClassException异常。 建议显示定义UID,如果不显示定义,JVM会自动产生一个值,这个值和编译器的实现有关,不稳定,可能在不同JVM环境下出现反序列化抛出InvalidClassException异常的情况。   在Eclipse中,提供两种方式显示定义UID,一种是“add default serial version ID”,默认值为1L;另一种是“add generated serial version ID”,默认值是一个很大的数,是根据  类的具体属性而生成,当类属性有变动时,该值会更改。     建议采用第一种自动生成方法,当对类进行了不兼容性修改时,需要修改UID。     采用第二种方法时,如果修改了属性,不重新生成UID时,默认值是不会变的,也可以正常反序列化,但不推荐,毕竟UID的值与实际不符。  对于继承关系,父类实现序列化接口,子类可以继承接口的实现,但需显示定义UID,因为父类UID类型为private static,不可被继承,同时子类作为单独的类需要单独的UID。 1、为什么要使用 (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、如何创建 以下内容参考: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类,然后创建这个对象,最后序列化它到一个文件。
  1.   
  2. import java.io.Serializable;     
  3. public class Person implements Serializable {       
  4.     private String name;       
  5.     public String getName() {   
  6.         return name;   
  7.     }   
  8.     public void setName(String name) {   
  9.         this.name = name;   
  10.     }   
  11. }   
 
  1. import java.io.FileOutputStream;   
  2. import java.io.ObjectInputStream;   
  3. import java.io.ObjectOutputStream;   
  4.     
  5. public class WhySerialversionUID {     
  6. public static void main(String[] args) throws Exception {          
  7. Person personnew Person();   
  8. person.setName("jack");     
  9. ObjectOutputStream oo new ObjectOutputStream  (new FileOutputStream(new File("E://jack.test")));   
  10.                              oo.writeObject(person);   
  11. oo.close();   
 
  1. import java.io.FileOutputStream;   
  2. import java.io.ObjectInputStream;   
  3. import java.io.ObjectOutputStream;   
  4.     
  5. public class WhySerialversionUID {     
  6. public static void main(String[] args) throws Exception {     
  7.  ObjectInputStream ois new ObjectInputStream(new FileInputStream(new File("E://jack.test")));  
  8.            Person person = (Person)ois.readObject();      
  9.             String name= person.getName();  
  10.           System.Out.Print("name is: "+name);