java序列化 UID serialVersionUID詳解

簡介:

  簡單來說,Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,如果相同就認爲是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。

有兩種生成方式:
       一個是默認的1L,比如:private static final long serialVersionUID = 1L;
       一個是根據類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,比如:
       private static final   long     serialVersionUID = xxxxL;

兩種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.

兩種都可以,從JDK文檔也看不出這一點。我們只要保證在同一個類中,不同版本根據兼容需要,是否更改SerialVersionUid即可。對於第一種,需要了解哪些情況是可兼容的,哪些根本就不兼容。

參考文檔:http://java.sun.com/j2se/1.4/pdf/serial-spec.pdf

第一種方式,在可兼容的前提下,可以保留舊版本號,如果不兼容,或者想讓它不兼容,就手工遞增版本號。

1->2->3.....

第二種方式,是根據類的結構產生的hash值。增減一個屬性、方法等,都可能導致這個值產生變化。

  我想這種方式適用於這樣的場景:

  開發者認爲每次修改類後就需要生成新的版本號,不想向下兼容,操作就是刪除原有serialVesionUid聲明語句,再自動生成一下。

  個人認爲,一般採用第一種就行了,簡單。第二種能夠保證每次更改類結構後改變版本號,但還是要手工去生成,並不是修改了類,會提示你要去更新這個SerialVersionUid,所以雖然看上去很cool,實際上讓人很迷惑。

  當實現java.io.Serializable接口的實體(類)沒有顯式地定義一個名爲serialVersionUID,類型爲long的變量時,Java序列化機制會根據編譯的class自動生成一個serialVersionUID作序列化版本比較用,這種情況下,只有同一次編譯生成的class纔會生成相同的serialVersionUID ,並不穩定,這樣就可能在不同JVM環境下出現反序列化時報InvalidClassException異常。
  如果我們不希望通過編譯來強制劃分軟件版本,即實現序列化接口的實體能夠兼容先前版本,未作更改的類,就需要顯式地定義一個名爲serialVersionUID,類型爲long的變量,不修改這個變量值的序列化實體都可以相互進行串行化和反串行化。

 private static final   long     serialVersionUID = xxxxL;

這樣就顯式的聲明瞭序列化實體的UID,這種方式好像是1.5才支持的(有待再覈實)。



Hibernate的持久化,這個一般指的是將數據持久化到數據庫,和序列化並沒有直接關係。

Hibernate的POJO也並不要求必須實現Serializable接口,但是,作爲系統擴展考慮,應該把PO都實現Serializable接口,因爲如果這些對象需要緩存到磁盤上,或者在分佈式環境下使用,就必須序列化,最常見的例子就是ehcache、Memcached。key和value中的對象都必須是序列化的對象。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章