serialVersionUID 有什麼作用?該如何使用?

專注於Java領域優質技術,歡迎關注

問題

當一個對象實現 Serializable 接口時,多數 ide 會提示聲明一個靜態常量 serialVersionUID(版本標識),那 serialVersionUID 到底有什麼作用呢?應該如何使用 serialVersionUID ?

回答

serialVersionUID 是實現 Serializable 接口而來的,而 Serializable 則是應用於Java 對象序列化/反序列化。對象的序列化主要有兩種用途:

  • 把對象序列化成字節碼,保存到指定介質上(如磁盤等)
  • 用於網絡傳輸

現在反過來說就是,serialVersionUID 會影響到上述所提到的兩種行為。那到底會造成什麼影響呢?

java.io.Serializable doc 文檔,給出了一個相對詳細解釋:

serialVersionUID 是 Java 為每個序列化類產生的版本標識,可用來保證在反序列時,發送方發送的和接受方接收的是可兼容的對象。如果接收方接收的類的 serialVersionUID 與發送方發送的 serialVersionUID 不一致,進行反序列時會拋出 InvalidClassException。序列化的類可顯式聲明 serialVersionUID 的值,如下:

```
ANY-ACCESS-MODIFIER static final long serialVersionUID = 1L;
```

當顯式定義 serialVersionUID 的值時,Java 根據類的多個方面(具體可參考 Java 序列化規範)動態生成一個默認的 serialVersionUID 。儘管這樣,還是建議你在每一個序列化的類中顯式指定 serialVersionUID 的值,因為不同的 jdk 編譯很可能會生成不同的 serialVersionUID 默認值,進而導致在反序列化時拋出 InvalidClassExceptions 異常。所以,為了保證在不同的 jdk 編譯實現中,其 serialVersionUID 的值也一致,可序列化的類必須顯式指定 serialVersionUID 的值。另外,serialVersionUID 的修飾符最好是 private,因為 serialVersionUID 不能被繼承,所以建議使用 private 修飾 serialVersionUID。

舉例說明如下: 現在嘗試通過將一個類 Person 序列化到磁盤和反序列化來說明 serialVersionUID 的作用: Person 類如下:

serialVersionUID 有什麼作用?該如何使用?

簡單的測試一下:

serialVersionUID 有什麼作用?該如何使用?

測試發現沒有什麼問題。有一天,因發展需要, 需要在 Person 中增加了一個字段 email,如下:

serialVersionUID 有什麼作用?該如何使用?

這時我們假設和之前序列化到磁盤的 Person 類是兼容的,便不修改版本標識 serialVersionUID。再次測試如下

serialVersionUID 有什麼作用?該如何使用?

將以前序列化到磁盤的舊 Person 反序列化到新 Person 類時,沒有任何問題。

可當我們增加 email 字段後,不作向後兼容。即放棄原來序列化到磁盤的 Person 類,這時我們可以將版本標識提高,如下:

private static final long serialVersionUID = 2L;

再次進行反序列化,則會報錯,如下:

java.io.InvalidClassException:Person local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

談到這裡,我們大概可以清楚,serialVersionUID 就是控制版本是否兼容的,若我們認為修改的 Person 是向後兼容的,則不修改 serialVersionUID;反之,則提高 serialVersionUID的值。再回到一開始的問題,為什麼 ide 會提示聲明 serialVersionUID 的值呢?

因為若不顯式定義 serialVersionUID 的值,Java 會根據類細節自動生成 serialVersionUID 的值,如果對類的源代碼作了修改,再重新編譯,新生成的類文件的serialVersionUID的取值有可能也會發生變化。類的serialVersionUID的默認值完全依賴於Java編譯器的實現,對於同一個類,用不同的Java編譯器編譯,也有可能會導致不同的serialVersionUID。所以 ide 才會提示聲明 serialVersionUID 的值。


分享到:


相關文章: