serialVersionUID的作用

应该大家都大概知道Java中序列化和反序列化的意思,序列化就是把一个Java对象转换成二进制进行磁盘上传输或者网络流的传输,反序列化的意思就是把

这个接受到的二进制流重新组装成原来的对象逆过程。它们在Java中分别是通过ObjectInputStream和 

ObjectInputStream这两个类来实现的(以下分别用ois和oos来简称)。

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即可。

如果你没有考虑到兼容性问题时,就把它关掉,不过有这个功能是好的,只要任何类别实现了Serializable这个接口的话,如果没有加入

serialVersionUID,Eclipse都会给你warning提示,这个serialVersionUID为了让该类别

Serializable向后兼容。 

如果你的类Serialized存到硬盘上面后,可是后来你却更改了类别的field(增加或减少或改名),当你Deserialize时,就会出现Exception的,这样就会造成不兼容性的问题。 

但当serialVersionUID相同时,它就会将不一样的field以type的预设值Deserialize,可避开不兼容性问题。


一个对象序列化的接口,一个类只有实现了Serializable接口,它的对象才是可序列化的。因此如果要序列化某些类的对象,这些类就必须实现Serializable接口。而实际上,Serializable是一个空接口,没有什么具体内容,它的目的只是简单的标识一个类的对象可以被序列化。

什么情况下需要序列化 

a)当你想把的内存中的对象写入到硬盘的时候;

b)当你想用套接字在网络上传送对象的时候;

c)当你想通过RMI传输对象的时候;

再稍微解释一下:a)比如说你的内存不够用了,那计算机就要将内存里面的一部分对象暂时的保存到硬盘中,等到要用的时候再读入到内存中,硬盘的那部分存储空间就是所谓的虚拟内存。在比如过你要将某个特定的对象保存到文件中,我隔几天在把它拿出来用,那么这时候就要实现Serializable接口

b)在进行java的Socket编程的时候,你有时候可能要传输某一类的对象,那么也就要实现Serializable接口;最常见的你传输一个字符串,它是JDK里面的类,也实现了Serializable接口,所以可以在网络上传输。

c)如果要通过远程的方法调用(RMI)去调用一个远程对象的方法,如在计算机A中调用另一台计算机B的对象的方法,那么你需要通过JNDI服务获取计算机B目标对象的引用,将对象从B传送到A,就需要实现序列化接口。



1、序列化是干什么的?

   

    

简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保

存object states,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。


2、什么情况下需要序列化  

    a)当你想把的内存中的对象状态保存到一个文件中或者数据库中时候;

    b)当你想用套接字在网络上传送对象的时候;

    c)当你想通过RMI传输对象的时候;


3、当对一个对象实现序列化时,究竟发生了什么?

    在没有序列化前,每个保存在堆(Heap)中的对象都有相应的状态(state),即实例变量(instance ariable)比如:

   


  

  

  

  

  

   

   

   

   

   

java 代码

  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

    

  Foo  myFoo = new Foo();  

 

    

  1.   myFoo .setWidth(37);  

 

    

  1.   myFoo.setHeight(70); 
     

 

   


  

  

  

  

  

      

 

当通过下面的代码序列化之后,MyFoo对象中的width和Height实例变量的值(37,70)都被保存到foo.ser文件中,这样以后又可以把

它从文件中读出来,重新在堆中创建原来的对象。当然保存时候不仅仅是保存对象的实例变量的值,JVM还要保存一些小量信息,比如类的类型等以便恢复原来的

对象。


  

  

  

  

  

   

   

   

   

   

java 代码

  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

    

 FileOutputStream fs = new FileOutputStream("foo.ser");  

 

    

  1.  ObjectOutputStream os = new ObjectOutputStream(fs);  

 

    

 os.writeObject(myFoo);  

 

    

  1.  
  2.  

 

    

 

  1.  

 

   


  

  

  

  

  


4、实现序列化(保存到一个文件)的步骤

  a)Make a FileOutputStream    

     java 代码

     FileOutputStream fs = new FileOutputStream("foo.ser");           

  b)Make a ObjectOutputStream           


  

  

  

  

  

   

   

   

   

   

     java 代码 

   

   

   

   

   

     ObjectOutputStream os =  new ObjectOutputStream(fs); 

  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

   


  

  

  

  

  

  c)write the object


  

  

  

  

  

   

   

   

   

   

     java 代码

   

   

   

   

   

     os.writeObject(myObject1);   

   

   

   

   

   

     os.writeObject(myObject2);   

   

   

   

   

   

     os.writeObject(myObject3);  

  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

   


  

  

  

  

  

  d) close the ObjectOutputStream


  

  

  

  

  

   

   

   

   

   

     java 代码 

   

   

   

   

   

     os.close();  

   

   

   

   

   


   

   

   

   

   


  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

   


  

  

  

  

  

5、举例说明



  

  

  

  

  


   

   

   

   

   java 代码

  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

   


  

  

  

  

  


  

  

  

  

  


   

   

   

   

   

 

    

  import java.io.*;

 

    

  1.     

 

    

  public class  Box implements Serializable  

 

    

  1.   {  

 

    

      private int width;  

 

    

  1.       private int height;  

 

    

    

 

    

  1.       public void setWidth(int width){  

 

    

          this.width  = width;  

 

    

  1.       }  

 

    

      public void setHeight(int height){  

 

    

  1.           this.height = height;  

 

    

      }  

 

    

  1.     

 

    

      public static void main(String[] args){  

 

    

  1.           Box myBox = new Box();  

 

    

          myBox.setWidth(50);  

 

    

  1.           myBox.setHeight(30);  

 

    

    

 

    

  1.           try{  

 

    

              FileOutputStream fs = new FileOutputStream("foo.ser");  

 

    

  1.               ObjectOutputStream os =  new ObjectOutputStream(fs);  

 

    

              os.writeObject(myBox);  

 

    

  1.               os.close();  

 

    

          }catch(Exception ex){  

 

    

  1.               ex.printStackTrace();  

 

    

          }  

 

    

  1.       }  

 

    

  1.   } 

 

   


  

  

  

  

  


6、相关注意事项

    a)序列化时,只对对象的状态进行保存,而不管对象的方法;

    b)当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;

    c)当一个对象的实例变量引用其他对象,序列化该对象时也把引用对象进行序列化;

    d)并非所有的对象都可以序列化,,至于为什么不可以,有很多原因了,比如:

        1.安全方面的原因,比如一个对象拥有private,public等field,对于一个要传输的对象,比如写到文件,或者进行rmi传输  等等,在序列化进行传输的过程中,这个对象的private等域是不受保护的。

       2. 资源分配方面的原因,比如socket,thread类,如果可以序列化,进行传输或者保存,也无法对他们进行重新的资源分  配,而且,也是没有必要这样实现

你可能感兴趣的:(serialVersionUID的作用)