我有一个用于不可变使用的类,因此我想标记所有字段final
。
然而,该类被序列化和反序列化以通过网络发送。为此,需要一个空的构造函数。这会阻止我创建最终字段。
我确定这是一个相当普遍的问题,但我找不到解决方案。我应该如何进行?
我有一个用于不可变使用的类,因此我想标记所有字段final
。
然而,该类被序列化和反序列化以通过网络发送。为此,需要一个空的构造函数。这会阻止我创建最终字段。
我确定这是一个相当普遍的问题,但我找不到解决方案。我应该如何进行?
不需要无参数构造函数。派生最多的不可序列化类确实需要可用于派生最少的可序列化类的无参数构造函数。
如果您需要更改 a 中的字段readObject
,请通过readResolve
and使用串行代理writeReplace
。
在典型的序列化情况下,类不需要具有空的构造函数或非最终字段即可序列化。
现在,如果您必须自己进行序列化,或者您需要子类化一个不实现 Serializable 的类,那就另当别论了。
因此,您需要提供更多有关您遇到问题的详细信息。
此问题是Java 语言上的一个开放错误。(请注意,这只适用于必须手动进行序列化的情况,例如使用 readObject)
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 的概述:Java 中的 Serializable 和 Externalizable 有什么区别?,这里是官方的 Java 教程:http: //java.sun.com/docs/books/tutorial/javabeans/persistence/index.html。
作为记录,因为我有一个类似的问题:
我有一条消息“ java.io.InvalidClassException: com.example.stuff.FooBar; com.example.stuff.FooBar; no valid constructor ”
我认为这是因为它缺少默认构造函数。但是上面的答案确认它不是强制性的(但是我们的应用程序使用了一个确实需要默认构造函数的旧序列化程序,因此可能会出现这种情况)。
然后我找到了一个页面,上面写着:
如果为继承而设计的类不可序列化,则可能无法编写可序列化的子类。具体来说,如果超类不提供可访问的无参数构造函数,那将是不可能的。
因此我得到的信息,我想。看来核心问题是经典的:我声明一个类是可序列化的,但超类不是!我将 Serializable 接口在层次结构中向上移动,一切都很好。
但是这个消息有点误导...... :-)
不需要无参数构造函数。让我们阅读源代码:
// 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);
}
}