深入理解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中的對象都必須是序列化的對象。

發佈了5 篇原創文章 · 獲贊 4 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章