2010-07-19 269 views
39

我知道我可以使用serialVersionUID來控制類的版本。而且我讀到,我可以添加或刪除字段,並且類仍然兼容,它只會使用默認值。我什麼時候需要更改serialVersionUID?

必須我更改serialVersionUID?

+0

相關https://stackoverflow.com/questions/3678136/managing-several-versions-of-serialized-java-objects/14946099#14946099 – Gray 2017-12-14 17:55:21

回答

44

當對類的結構進行不兼容的更改時,理想情況下應該更改serialVersionUID字段的值。在Java Object Serialization Specification中列出了不兼容更改的完整列表 。

要進一步擴展,對類的不兼容更改將阻止反序列化機制創建對象的實例,因爲流中的信息未映射到當前類定義。

+0

謝謝,很好的回答 – Kyle 2010-07-20 04:49:38

+1

不,不是。規範中列出的不兼容更改是那些嘗試時會導致異常的更改。那些僅僅不映射到當前類定義的是*兼容*變化,並且還有一長串的變化。 – EJP 2014-08-19 09:24:30

+0

*爲了進一步擴展,不兼容的更改會阻止反序列化機制創建實例*:這個答案不等於說我應該更改'serialVersionUID'來使反序列化機制拋出異常,即使它可以已經做到了,沒有我的幫助,因爲這是一個不兼容的變化,阻止上述機制的工作?如果是這樣的話,我認爲應該澄清一下這很有用。 (我在這裏懷疑是因爲[EJP的回答](https://stackoverflow.com/a/3288280/1036728)更有意義。) – antak 2018-03-05 07:02:28

3

如果您在Serializable類中未指定serialVersionUID字段,則Java編譯器將爲您指定一個字段 - 本質上它是類名稱,接口名稱,方法和類字段的散列。但是,隨時可以更改方法,因此如果需要更改存儲類的反序列化方式,可以覆蓋readObject方法。但是,如果您在代碼中指定了serialVersionUID字段,即使您做出不兼容的更改(即運行時會導致異常),編譯器也不會覆蓋該更改 - 您的IDE或編譯器不會給出警告。 (編輯 - 謝謝EJP)如果您想輕鬆地檢查編譯器如何查看某些更改,Eclipse等IDE可以爲您插入編譯器的UID。

如果您經常進行更改,請保留舊版本的磁盤文件以測試反序列化。您可以編寫單元測試來嘗試讀入舊文件,並查看它是否有效或者是否完全不兼容。

一個告誡,我親身體驗過與Serializable類最初打算用於長期存儲的設計不當的痛苦。例如,將GUI元素存儲在磁盤上,而不是在需要時創建它們。問問自己,如果Serializable確實是保存數據的最佳方式。

+0

+1用於指出存儲數據的Serializable問題,特別是在使用你自己的類(JDK中的類至少足夠穩定)。 – Thilo 2010-07-20 06:42:32

+0

'...不兼容的更改會導致運行時異常' - 您需要澄清這一點。你會得到IOExceptions,而不是RuntimeExceptions。 – EJP 2010-07-21 23:57:19

+0

@EJP你說得對,我可以說更好。您將在運行時獲得IOEXception /正是我的意思 - 您的IDE或編譯器不會提前提醒您。 – 2010-07-22 22:15:38

16

每當你改變課程時,經常重複的關於改變serialVersionUID的咒語是完全的,完全是無稽之談。請參閱this Sun article,它們在其網站上重新發布,並在收購後遷移到Oracle技術網絡。

你應該改變serialVersionUID只有當你刻意要打破兼容所有現有的序列化,例如,當改變你的類將使它所以語義不同,你別無選擇 - 在這種情況下,你應該真的多次想到你實際上在做什麼。

在所有其他情況下,你應該胸圍你鍋爐試圖使用自定義readObject()/writeObject()和/或writeReplace()/readResolve()方法和/或serialFields註解,這樣就可以繼續從那些現有的序列化閱讀的對象。一旦你打破了,你是在頭痛,真是噩夢。

+0

該URL不可用。你能更新它嗎? – 2015-04-24 15:37:19

+1

這個答案可以通過完全陳述你不同意的內容,或者你認爲你的鏈接文章所倡導的內容來改善。閱讀這篇文章,我看不到太陽是什麼「不同意」。 – DavidS 2015-12-03 23:27:13

+0

如果我爲班級添加了一個新字段,該怎麼辦?此更改仍然兼容:不會拋出異常。但該字段不包含任何信息,因此在語義上它不兼容。在這種情況下,我應該增加UID嗎? – damluar 2016-11-02 11:31:51

-1

您可以將serialiVersionUID設置爲類的生命期相同的值。 (並非總是一個好主意)注意:如果需要,可以使用readObject/writeObject實現自己的序列化版本檢查策略,並保持UID不變。

您必須改變它的唯一時間是如果您已經將某些數據序列化到文件並且您想要讀取它。如果由於任何原因它已經改變,你必須將serialiVersionUID設置爲文件中的版本,以期望能夠讀取數據。

+0

這是一個跡象,你不應該改變它在第一個地方。 – EJP 2010-08-14 06:52:00

相關問題