深入理解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
- 序列化-serialVersionUID作用UI
- 深入理解Java序列化機制Java
- 深入理解Java中的AQSJavaAQS
- 深入理解Java中的鎖Java
- 深入理解 Java 中的 LambdaJava
- Java之serialVersionUIDJavaUI
- 深入理解Java中的逃逸分析Java
- 深入理解Java中的鎖(二)Java
- 深入理解Java中的鎖(一)Java
- 深入理解Java中的Garbage CollectionJava
- 深入理解RPC框架的序列化方案RPC框架
- 深入理解Java中的不可變物件Java物件
- JAVA中鎖的深入理解與解析Java
- 深入理解Java中的volatile關鍵字Java
- Java中Thread 和Runnable 深入理解Javathread
- 深入理解 Java 中 SPI 機制Java
- JSON序列化之旅:深入理解.NET中的JsonResult與自定義ContractResolverJSON
- Java serialVersionUID 有什麼作用?JavaUI
- 深入理解Java ClassLoader及在 JavaAgent 中的應用Java
- 深入理解Java PriorityQueueJava
- 深入理解 Java 方法Java
- Java:IO:深入理解Java
- 深入理解Java反射Java反射
- JS中this的深入理解JS
- 深入理解Js中的thisJS
- 夯實Java基礎系列13:深入理解Java中的泛型Java泛型
- Java中的序列化與反序列化Java
- 深入理解Java中的底層阻塞原理及實現Java
- 深入理解Java中的fail-fast和fail-safeJavaAIAST
- 深入理解 Java 泛型Java泛型
- 深入理解 Java 註解Java
- Java集合——深入理解HashMapJavaHashMap
- 深入理解Java異常Java
- 深入理解Java反射(一)Java反射
- 深入理解Java泛型Java泛型
- 深入理解 Java 列舉Java
- 深入理解 Java 陣列Java陣列
- 深入理解JavaScirpt中的this(轉)Java