2009-11-02 90 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); 
    } 
}