【Java】serialVersionUID的做用

簡單來講,Java的序列化機制是經過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,若是相同就認爲是一致的,能夠進行反序列化,不然就會出現序列化版本不一致的異常。(InvalidCastException)java

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便可。
當實現java.io.Serializable接口的實體(類)沒有顯式地定義一個名爲serialVersionUID,類型爲long的變量時,Java序列化機制會根據編譯的class(它經過類名,方法名等諸多因素通過計算而得,理論上是一一映射的關係,也就是惟一的)自動生成一個serialVersionUID做序列化版本比較用,這種狀況下,若是class文件(類名,方法明等)沒有發生變化(增長空格,換行,增長註釋,等等),就算再編譯屢次,serialVersionUID也不會變化的.測試

若是咱們不但願經過編譯來強制劃分軟件版本,即實現序列化接口的實體可以兼容先前版本,未做更改的類,就須要顯式地定義一個名爲serialVersionUID,類型爲long的變量,不修改這個變量值的序列化實體均可以相互進行串行化和反串行化。this

若是你沒有考慮到兼容性問題時,就把它關掉,不過有這個功能是好的,只要任何類別實現了Serializable這個接口的話,若是沒有加入 serialVersionUID,Eclipse都會給你warning提示,這個serialVersionUID爲了讓該類別 Serializable向後兼容。.net

問題一:假設有A端和B端,若是2處的serialVersionUID不一致,會產生什麼錯誤呢?接口

問題二:假設2處serialVersionUID一致,若是A端增長一個字段,B端不變,會是什麼狀況呢?ip

問題三:假設2處serialVersionUID一致,若是B段增長一個字段,A端不變,會是什麼狀況呢?get

問題四:假設2處serialVersionUID一致,若是A端減小一個字段,B端不變,會是什麼狀況呢?it

問題五:假設2處serialVersionUID一致,若是B端減小一個字段,A端不變,會是什麼狀況呢?io

 

例子以下:寫2個類,類名相同,字段相同,方法相同.放在不一樣的包裏,來模仿A端和B端.編譯

實體類:在本例中,在測試類SerialTest執行前表明A端,而後,在測試類DeserialTest執行前表明B端.

package com.test; import java.io.Serializable;

public class Serial implements Serializable{ /**   *   */ private static final long serialVersionUID = 6977402643848374753L; int id;       String name;       public Serial(int id, String name) {           this.id = id;           this.name = name;       }       public String toString() {           return "DATA: " + id + " " +name;         }   }

 

測試類,表明A端的序列化

package com.test.serializable;

import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream;

public class SerialTest {

/**   * @param args   */ public static void main(String[] args) {   // TODO Auto-generated method stub   Serial serial1 = new Serial(1,"song");   System.out.println("Object Serial"+serial1);     try {    FileOutputStream fos = new FileOutputStream("serialTest.txt");    ObjectOutputStream oos = new ObjectOutputStream(fos);    oos.writeObject(serial1);    oos.flush();    oos.close();         } catch (FileNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } } }

測試類,表明B端的反序列化

package com.test.serializable;

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream;

public class DeserialTest {

/**   * @param args   */ public static void main(String[] args) {   // TODO Auto-generated method stub   Serial serial2 ;   try {    FileInputStream fis = new FileInputStream("serialTest.txt");    ObjectInputStream ois = new ObjectInputStream(fis);    serial2 = (Serial)ois.readObject();    ois.close();    System.out.println("Object Deserial"+serial2);   } catch (FileNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (ClassNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }   }

}

問題一:假設有A端和B端,若是2處的serialVersionUID不一致,會產生什麼錯誤呢?

答案以下:

1)先執行測試類SerialTest,而後修改serialVersion值(或註釋掉serialVersion並編譯),再執行測試類DeserialTest,報錯:

java.io.InvalidClassException: com.test.serializable.Serial; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 11

2)A端和B端都沒顯示的寫serialVersionUID,實體類沒有改動(若是class文件(類名,方法明等)沒有發生變化(增長空格,換行,增長註釋,等等),).序列化,反序列化正常.

 

問題二:假設2處serialVersionUDI一致,若是A端增長一個字段,B端不變,會是什麼狀況呢?

答案二: 序列化,反序列化正常,A端增長的字段丟失(被B端忽略).

問題五:假設2處serialVersionUID一致,若是B端減小一個字段,A端不變,會是什麼狀況呢?

答案:與問題二相似,序列化,反序列化正常,B端字段少於A端,A端多的字段值丟失(被B端忽略).

 

問題三:假設2處serialVersionUID一致,若是B段增長一個字段,A端不變,會是什麼狀況呢?

問題四:假設2處serialVersionUID一致,若是A端減小一個字段,B端不變,會是什麼狀況呢?(與問題三相似,四答案:序列化,反序列化正常,B端字段多餘A端,B端多出的字段被賦予對應類型的默認值)

答案三: 序列化,反序列化正常,B端新增長的int字段被賦予了默認值0.  

例子以下:

3)先執行SerialTest,而後在實體類增長一個字段age,再執行測試類DeserialTest.

package com.test.serializable;

import java.io.Serializable;

public class Serial implements Serializable {

/**   *   */ private static final long serialVersionUID = -2337937881709830076L;

/**   *   */ //private static final long serialVersionUID = 1L; int id;       

    String name;       public Serial(int id, String name) {           this.id = id;           this.name = name;       }       public String toString() {           return "DATA: " + id + " " +name;         }     public int age ;//在B端增長一個新字段 }

相應的修改測試類DeserialTest,打印出age的值.

package com.test.serializable;

import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.ObjectInputStream;

public class DeserialTest {

/**   * @param args   */ public static void main(String[] args) {   // TODO Auto-generated method stub   Serial serial2 ;   try {    FileInputStream fis = new FileInputStream("serialTest.txt");    ObjectInputStream ois = new ObjectInputStream(fis);    serial2 = (Serial)ois.readObject();    ois.close();    System.out.println("Object Deserial"+serial2+" age="+serial2.age);   } catch (FileNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (IOException e) {    // TODO Auto-generated catch block    e.printStackTrace();   } catch (ClassNotFoundException e) {    // TODO Auto-generated catch block    e.printStackTrace();   }   }

}

打印結果以下:

Object DeserialDATA: 1 song age=0

說明序列化,反序列化正常,B端新增長的int字段被賦予了默認值0.

 

上面的狀況對增長/減小 字段/方法 都適用.

//但當serialVersionUID相同時,它就會將不同的field以type的預設值Deserialize,可避開不兼容性問題。

相關文章
相關標籤/搜索