2009-11-02 59 views
13

我有一個類用於不可變的使用,因此我想標記所有字段final序列化和不可變的對象

但是,該類被序列化並反序列化以通過網絡發送。爲了這個工作,需要一個空的構造函數。這可以防止我創建最終字段。

我敢肯定這是一個相當普遍的問題,但我找不到解決方案。我應該如何繼續?

回答

7

在典型的序列化情況下,並不要求類有一個空的構造函數或非final字段可序列化。

現在,如果你必須做你自己的序列化,或者你需要繼承一個沒有實現Serializable的類,那是不同的故事。

所以你需要提供一些你如何解決問題的更多細節。

+1

謝謝,我用的是序列化的典型方法,但一直提供一個空的構造函數,這是我怎麼想它的工作。 – Pool 2009-11-03 01:16:23

6

不需要無參數構造函數。最派生的不可序列化類確實需要一個無參數構造函數,可用於最不派生的可序列化類。

如果您需要對readObject內的字段進行變異,請使用通過readResolvewriteReplace的串行代理。

5

此問題是open bug on the Java language。 (請注意,這僅適用於必須手動執行序列化的情況,例如使用readObject)

+0

從評估:「該問題適用於除類的可序列化字段以外的最終實例字段」,所以在標準情況下它工作正常。尼克似乎在做一些不同的事情。 – Yishai 2009-11-02 19:30:18

+0

啊是的,我應該添加一個免責聲明,這隻適用於如果你必須鉤入readObject或類似的東西。 – 2009-11-02 19:38:08

3

要回應上述內容,如果正在執行java.io.Serializable接口的路由,則不需要無參數構造函數。例如,看一下java.lang.Integer源代碼,例如一個簡單的可序列化/不可變類,它有兩個構造函數:一個接受一個int,另一個接受一個String。源代碼:http://www.docjar.com/html/api/java/lang/Integer.java.html。 Javadoc:http://java.sun.com/javase/6/docs/api/java/lang/Integer.html

同樣取決於你班級的複雜程度和你在做什麼,你可以考慮通過java.io.Externalizable接口實現序列化(儘管有些人認爲它過時了,並且它需要一個無參數構造函數)。以下是關於SO的概述:What is the difference between Serializable and Externalizable in Java?,以下是官方的Java教程:http://java.sun.com/docs/books/tutorial/javabeans/persistence/index.html

3

爲了記錄在案,因爲我有一個類似的問題:
我有一個消息「java.io.InvalidClassException:com.example.stuff.FooBar; com.example.stuff.FooBar;沒有有效的構造

我認爲這是因爲它缺少默認的構造函數。但上面的答案確認它不是強制性的(但我​​們的應用程序使用了一個確實需要默認構造函數的舊序列化程序,因此可能會出現這種情況)。

然後我發現了一個網頁,指出:

如果是專爲繼承一個類是不可序列,它 可能無法寫一個序列化的子類。具體來說,如果超類沒有提供可訪問的 無參數構造函數,那麼它將不可能爲 。

因此,我得到的消息,我想。似乎核心問題是古典的:我宣稱一個類是可序列化的,但超類不是!我將Serializable接口移到層次結構中,一切都很順利。

但該消息是有點誤導... :-)

0

不需要一個無參數的構造函數。讓我們閱讀源代碼:

// java.io.ObjectStreamClass 
private static Constructor<?> getSerializableConstructor(Class<?> cl) { 
    Class<?> initCl = cl; 
    while (Serializable.class.isAssignableFrom(initCl)) { 
     if ((initCl = initCl.getSuperclass()) == null) { 
      return null; 
     } 
    } 
    ... 
} 

所以,實際上是無參數的構造函數是在類型層次最近沒有Serializable類所需。

這意味着可以序列化以下類Domain

class Domain implements Serializable { 
    private final int a; 

    public Domain(int a) { 
     this.a = a; 
    } 
} 

但類Son不能:

class Father{ 
    private final int a; 

    public Father(int a) { 
    this.a = a; 
    } 
} 

class Son extends Father implements Serializable { 
    public Son(int a) { 
    super(a); 
    } 
}