2012-04-20 42 views
2

序列化標識如何存儲在對象的實例中?Java中的序列化版本uid

我們在Java中聲明的序列化ID是靜態字段;而靜態字段不是序列化的。

然後應該有一些方法來存儲靜態最終字段。 java如何做到這一點?

回答

2

如果你看看java.io.ObjectStreamClass那裏你可以看到它實際上是被序列化的。下面的方法:

java.io.ObjectOutputStream.writeClassDescriptor(ObjectStreamClass)

調用它調用下面的方法的方法:

java.io.ObjectStreamClass.getSerialVersionUID()

在調用哪個要麼計算serialVersionUID或者使用一個類中聲明,發現之前到以下方法:

java.io.ObjectStreamClass.getDeclaredSUID(Class)

所以看起來這個靜態字段是一個例外,因爲規則中沒有對靜態字段進行序列化。如何讀取它here

3

serialVersionUID不存儲在「序列化」對象的實例中,因爲它是一個靜態字段(它是類的一部分,而不是對象的一部分)。

因此,如果編譯的字節碼是實際定義的,那麼它是stored,否則就是計算它。在java specification的詞中:

如果類已經定義了serialVersionUID,它將從類中檢索。如果serialVersionUID>未由類定義,則從虛擬機中類的定義計算。如果>指定的類不是可序列化或可外部化的,則返回null。

Stream Unique Identifiers section中,說明了用於這種計算的算法。

這一段值得注意(這就是爲什麼當實現Serializable的類沒有明確定義serialVersionUID時IDE通常會顯示警告)。

:強烈建議所有可序列化類中明確聲明的serialVersionUID值,因爲默認serialVersionUID的計算是對類的詳細信息高度敏感,可能取決於編譯器實現變化,從而可能導致在反序列化期間意外的serialVersionUID衝突,導致反序列化失敗。

+0

@downvoter:你能評價你downvote? – jalopaba 2012-06-12 08:37:48

+0

「相對」downvote。必須確保Jiri的更好的答案在最前面(否則不會降低)。你完全忽略了這個問題的核心,那就是JVM如何知道序列化數據的版本(如果它的UID沒有寫入流中,那當然是,即使它是靜態字段)。 – Thilo 2012-06-12 08:41:35

0

serialVersionUID是序列化運行時使用的特殊字段。這些都在Java文檔中描述爲java.lang.Serializable

2

串行版本UID未存儲在對象中;它是一個靜態字段,因此它存儲在類定義中。發生什麼事是,當你序列化一個對象時,關於它的類的信息也必須被存儲;否則將無法對對象進行序列化。存儲在類中的信息包括其名稱和它的序列版本UID。

你可以在這裏閱讀整個協議:http://docs.oracle.com/javase/6/docs/platform/serialization/spec/protocol.html

總之,對於一個新的對象的條目都恰好是:

newObject: 
    TC_OBJECT classDesc newHandle classdata[] 

這裏classDesc是類的描述符可以是一個宣言一個新的類,一個空引用或對之前聲明的類的引用:

classDesc: 
    newClassDesc 
    nullReference 
    (ClassDesc)prevObject 

新類的聲明建立了類的名稱和序列版本UID,可用於以後參考它的手柄,以及其他信息編碼爲classDescInfo類:

newClassDesc: 
    TC_CLASSDESC className serialVersionUID newHandle classDescInfo