作者:fbysss
msn:jameslastchina@hotmail.com
blog:blog.csdn.net/fbysss
聲明:本文由fbysss原創,轉載請註明出處
關鍵字: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中的對象都必須是序列化的對象。