深入理解Java序列化中的SerialVersionUid
一、前言
SerialVersionUid,簡言之,其目的是序列化物件版本控制,有關各版本反序列化時是否相容。如果在新版本中這個值修改了,新版本就不相容舊版本,反序列化時會丟擲InvalidClassException異常。如果修改較小,比如僅僅是增加了一個屬性,我們希望向下相容,老版本的資料都能保留,那就不用修改;如果我們刪除了一個屬性,或者更改了類的繼承關係,必然不相容舊資料,這時就應該手動更新版本號,即SerialVersionUid。
關於其定義,可參考JDK文件:http://download.oracle.com/javase/1.5.0/docs/api/java/io/Serializable.html
二、問題
1.如果不顯式設定SerialVersionUid,有什麼後果?
jdk文件中有解釋,建議我們顯式宣告,因為如果不宣告,JVM會為我們自動產生一個值,但這個值和編譯器的實現相關,並不穩定,這樣就可能在不同JVM環境下出現反序列化時報InvalidClassException異常。
...it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations...
2.兩種SerialVersionUid有什麼區別?
在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宣告語句,再自動生成一下。
個人認為,一般採用第一種就行了,簡單。第二種能夠保證每次更改類結構後改變版本號,但還是要手工去生成,並不是修改了類,會提示你要去更新這個SerialVersionUid,所以雖然看上去很cool,實際上讓人很迷惑。
參考:
1.一篇較好的關於serialVesionUid的說明:
http://www.mkyong.com/java-best-practices/understand-the-serialversionuid/
2.serialVesionUid相關討論
http://stackoverflow.com/questions/888335/why-generate-long-serialversionuid-instead-of-a-simple-1l
3.compiler-generated ID生成演算法
http://java.sun.com/javase/6/docs/platform/serialization/spec/class.html#4100
其他相關問題:
Hibernate的持久化,這個一般指的是將資料持久化到資料庫,和序列化並沒有直接關係。
Hibernate的POJO也並不要求必須實現Serializable介面,但是,作為系統擴充套件考慮,應該把PO都實現Serializable介面,因為如果這些物件需要快取到磁碟上,或者在分散式環境下使用,就必須序列化,最常見的例子就是ehcache、Memcached。key和value中的物件都必須是序列化的物件。
相關文章
- 深入理解 Java 序列化Java
- 深入理解Java物件序列化Java物件
- 深入理解Java序列化機制Java
- 序列化-serialVersionUID作用UI
- Java中serialVersionUID的解釋JavaUI
- 深入理解Java中的鎖Java
- 深入理解 Java 中的 LambdaJava
- 深入理解Java中的AQSJavaAQS
- 深入理解Java中的逃逸分析Java
- 深入理解Java中的鎖(一)Java
- 深入理解Java中的鎖(二)Java
- 深入理解Java中的Garbage CollectionJava
- Java中的ThreadLocal深入理解Javathread
- JAVA中鎖的深入理解與解析Java
- 深入理解Java中的不可變物件Java物件
- 深入理解 Java 中的 try-with-resourceJava
- 深入分析Java的序列化與反序列化Java
- 理解Java物件序列化Java物件
- 深入理解RPC框架的序列化方案RPC框架
- 深入理解 Java 中 SPI 機制Java
- Java之serialVersionUIDJavaUI
- 深入理解Java中的HashMap的實現原理JavaHashMap
- java中的序列化Java
- 深入理解Java中的volatile關鍵字Java
- 深入理解Java中的final關鍵字Java
- 深入理解java中的組合和繼承Java繼承
- 深入理解Java中的記憶體洩漏Java記憶體
- Java中HashMap和TreeMap的區別深入理解JavaHashMap
- Java中Thread 和Runnable 深入理解Javathread
- 深入理解 Java 中 protected 修飾符Java
- Java執行緒中斷的本質深入理解Java執行緒
- JS中this的深入理解JS
- 深入理解Js中的thisJS
- 深入理解Java的==和equalsJava
- 深入探討、理解Java的CLASSPATHJava
- 夯實Java基礎系列13:深入理解Java中的泛型Java泛型
- 【Java基礎】序列化與反序列化深入分析Java
- 深入理解Java PriorityQueueJava