如果您曾經實現過
Serializable接口,則必須遇到此警告消息
The serializable class xxx does not declare a static final serialVersionUID field of type long
那么......什么是serialVersionUID?
serialVersionUID用作Serializable類中的版本控件。如果您沒有顯式聲明serialVersionUID,JVM將根據您的Serializable類的各個方面自動為您執行此操作,如
Java(TM)對象序列化規范中所述。
1. SerialVersionUID示例
上面的語句在開頭有點難以理解(至少我做過),讓我們開始一個例子來了解Serializable類如何使用SerialVersionUID來實現版本控制。
1.1 Address.java
serialVersionUID為1L的可序列化類。
import java.io.Serializable; public class Address implements Serializable{ private static final long serialVersionUID = 1L; String street; String country; public void setStreet(String street){ this.street = street; } public void setCountry(String country){ this.country = country; } public String getStreet(){ return this.street; } public String getCountry(){ return this.country; } @Override public String toString() { return new StringBuffer(" Street : ") .append(this.street) .append(" Country : ") .append(this.country).toString(); } }
1.2 WriteObject.java
將Address對象寫入/序列化為文件的簡單類 - “c:\\ address.ser”。
import java.io.FileOutputStream; import java.io.ObjectOutputStream; public class WriteObject{ public static void main (String args[]) { Address address = new Address(); address.setStreet("wall street"); address.setCountry("united states"); try{ FileOutputStream fout = new FileOutputStream("c:\\address.ser"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(address); oos.close(); System.out.println("Done"); }catch(Exception ex){ ex.printStackTrace(); } } }
1.3 ReadObject.java
從文件中讀取/反序列化Address對象的簡單類 - “c:\\ address.ser”。
import java.io.FileInputStream; import java.io.ObjectInputStream; public class ReadObject{ public static void main (String args[]) { Address address; try{ FileInputStream fin = new FileInputStream("c:\\address.ser"); ObjectInputStream ois = new ObjectInputStream(fin); address = (Address) ois.readObject(); ois.close(); System.out.println(address); }catch(Exception ex){ ex.printStackTrace(); } } }
2.測試
讓我們做一些測試來演示serialVersionUID的使用。
2.1相同的serialVersionUID
相同的serialVersionUID,在反序列化過程中沒有問題
javac Address.java javac WriteObject.java javac ReadObject.java java WriteObject java ReadObject Street : wall street Country : united states
復制
2.2不同的serialVersionUID
在Address.java中,
將serialVersionUID更改為2L(它是1L),然后再次編譯它。
javac Address.java java ReadObject java.io.InvalidClassException: Address; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2 ... at ReadObject.main(ReadObject.java:14)
“
InvalidClassException”會引發,因為您使用serialVersionUID“1L”編寫了一個序列化類,但嘗試使用更新的序列化類serialVersionUID“2L”將其檢索回來。
serialVersionUID必須在序列化和反序列化過程中匹配。
什么時候應該更新你的serialVersionUID?
如果使用對可序列化類的某些不兼容的Java類型更改更新序列化類,則必須更新serialVersionUID。
有關可序列化類的兼容和不兼容Java類型更改的詳細信息,請參閱
Java對象序列化規范。
3.默認的serialVersionUID有什么問題?
如果沒有聲明serialVersionUID,JVM將使用自己的算法生成默認的SerialVersionUID,您可以在
此處檢查算法。
默認的serialVersionUID計算對類詳細信息非常敏感,可能因不同的JVM實現而異,並且在反序列化過程中會導致意外的InvalidClassExceptions。
3.1客戶端/服務器環境
- 客戶端在Windows中使用SUN的JVM。
- 服務器在Linux中使用JRockit。
客戶端通過套接字向服務器發送帶有默認生成的serialVersionUID(例如123L)的可序列化類,服務器可以在反序列化過程中生成不同的serialVersionUID(例如124L),並引發意外的InvalidClassExceptions。
3.2文件/數據庫環境
- App#1在Windows中使用SUN的JVM。
- App#2在Linux中使用JRockit。
序列化允許保存到文件或數據庫中。App#1默認生成serialVersionUID(例如123L)將可序列化類存儲到數據庫中,而App#2可能在反序列化過程中生成不同的serialVersionUID(例如124L),並引發意外的InvalidClassExceptions。
4.如何生成serialVersionUID
您可以使用JDK“
serialver”或Eclipse IDE自動生成serialVersionUID,詳見詳細信息。
結論
SUN強烈建議開發人員聲明serialVersionUID以避免上面列出的不同JVM問題,但我建議您應該了解什么是序列化,serialVersionUID如何實現版本控制以及您的類需要使用序列化的原因。了解serialVersionUID概念優於任何推薦的盲目。
本文參考:https://www.mkyong.com/java-best-practices/understand-the-serialversionuid/
參考
- http://en.wikipedia.org/wiki/List_of_JVM_implementations
- http://java.sun.com/javase/6/docs/platform/serialization/spec/class.html#4100
- http://stackoverflow.com/questions/419796/explicit-serialversionuid-considered-harmful
- http://en.wikipedia.org/wiki/Serialization#Java
- http://www.javaworld.com/javaworld/jw-02-2006/jw-0227-control.html?page=1
- http://www.javablogging.com/what-is-serialversionuid/
- http://java.dzone.com/articles/dont-ignore-serialversionuid
- http://www.java-forums.org/new-java/8196-serialversionuid.html
