java序列化和反序列化中的serialVersionUID有啥用

 1.什麼是序列化和反序列化java

  序列化就是將java對象轉成字節序列的過程;反序列化就是將字節序列轉成java對象的過程。算法

   java中,序列化的目的一種是須要將對象保存到硬盤上,一種是對象須要在網絡中傳輸json

2.序列化和反序列化的方式網絡

  序列化和反序列化有不少種方式,如JDK類庫中提供的序列化API、經常使用的json工具類等。本篇博客使用JDK提供的序列化API進行演示。重點說明serialVersionUID的做用。工具

  假設如今有一個Student類,咱們要對Student類進行序列化操做測試

  ①該類必須實現Serializable接口this

public class Student implements Serializable{

    private static final long serialVersionUID = -595470438262181967L;

    private String name ;
     
    private String sex;
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
    
}

  ②在main方法中執行序列化和反序列化操做spa

    public static void main(String[] args) throws Exception {
        
        //序列化
        OutputStream os = new FileOutputStream(new File("D://student.txt"));
        ObjectOutputStream oos = new ObjectOutputStream(os);
        Student student = new Student();
        student.setName("張三");
        student.setSex("男");
        oos.writeObject(student);
        
        //反序列化
        InputStream is = new FileInputStream(new File("D://student.txt"));
        ObjectInputStream ois = new ObjectInputStream(is);
        Student student1 = new Student();
        student1 = (Student) ois.readObject();
        System.out.println(student1.getName());
    }

  輸出結果:張三code

  即student1對象在反序列化時進行了賦值對象

3.爲何要serialVersionUID

  s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​號​,凡是實現Serializable接口的類都有一個表示序列化版本標識符的靜態變量。

  (1)下面進行測試,若是沒有s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D會出現什麼?

    ①去掉Student類中的s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D屬性。執行main方法,結果顯示序列化成功!輸出張三

    ②修改Student類,在Student類中添加number字段

public class Student implements Serializable{

    private String name ;
     
    private String sex;

    private String number;
    
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }
    
}

  不執行序列化方法,只執行反序列化方法,結果出現異常:

Exception in thread "main" java.io.InvalidClassException: com.iot.study.serialize.Student; local class incompatible: stream classdesc serialVersionUID = -595470438262181967, local class serialVersionUID = -4254220179260112271
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:621)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
    at com.iot.study.serialize.Client.main(Client.java:35)

  意思是原來序列化的時候(沒有指定serialVersionUID)硬盤存的class的 serialVersionUID = -595470438262181967,而當前class的serialVersionUID = -4254220179260112271。 兩者不同,沒法反序列化。

  緣由分析:

    serialVersionUID沒有指定時,java編譯器會自動給這個class進行一個摘要算法,相似於指紋算法,只要這個文件 多一個空格,獲得的UID就會大相徑庭的,能夠保證在這麼多類中,這個編號是惟一的。因此,添加了一個number字段後,因爲沒有顯指定 serialVersionUID,編譯器又爲咱們生成了一個UID,固然和前面保存在文件中的那個不會同樣了,因而就出現了2個序列化版本號不一致的錯誤。

  (2)指定serialVersionUID測試

  若是爲Student類顯示的指定serialVersionUID,那麼在序列化和反序列化的時候,即便修改了Student類中的部份內容,也能序列化成功。

4.serialVersionUID的取值

  serialVersionUID的取值是Java運行時環境根據類的內部細節自動生成的。若是對類的源代碼做了修改,再從新編譯,新生成的類文件的serialVersionUID的取值有可能也會發生變化。
  類的serialVersionUID的默認值徹底依賴於Java編譯器的實現,對於同一個類,用不一樣的Java編譯器編譯,有可能會致使不一樣的 serialVersionUID,也有可能相同。爲了提升serialVersionUID的獨立性和肯定性,強烈建議在一個可序列化類中顯示的定義serialVersionUID,爲它賦予明確的值

  顯式地定義serialVersionUID有兩種用途:    一、 在某些場合,但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備相同的serialVersionUID;    二、 在某些場合,不但願類的不一樣版本對序列化兼容,所以須要確保類的不一樣版本具備不一樣的serialVersionUID。

相關文章
相關標籤/搜索