内部类(Java)的序列化



我有一个Solution类,它包含内部类A、类B和类C。B类扩展A类,C类扩展B类。

我希望类C是可序列化的,所以我在类C和类Solution中实现了可序列化(类C是类Solution的内部类(。

因为类C扩展了类B,类B扩展了类A,所以我在类B和类A中创建了一个无参数构造函数(我不希望它们实现Serializable(。

所以下面的代码:

public class Solution implements Serializable {
public class A {
String name = "A";
public A(String name) {
this.name += name;
}
public A() {}
}

public class B extends A {
String name = "B";
public B(String name) {
super(name);
this.name += name;
}
public B() {}
}
public class C extends B implements Serializable {
String name;
public C(String name) {
super(name);
this.name = name;
}
}
}
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Solution.C c = new Solution().new C("C");
System.out.println(c.name);
System.out.println("serialization");
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\1.txt"));
oos.writeObject(c);
oos.close();
System.out.println("deserialization");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\1.txt"));
Solution.C c1 = (Solution.C) ois.readObject();
ois.close();
System.out.println(c1.name);
}
}

引发以下异常:

C
serialization
deserialization
Exception in thread "main" java.io.InvalidClassException: Test3.Solution$C; no valid constructor

在您的情况下,反序列化代码最终将为类Solution.C构造ObjectStreamClass的实例。在这个类的构造函数中,它试图找到一个合适的类的构造函数来反序列化。在您的情况下,它将调用ReflectionFactory#newConstructorForSerialization。以下是这种方法的文档说明:

返回一个构造函数,该构造函数分配cl的实例,然后通过调用其第一个不可序列化超类的无arg构造函数来初始化该实例。这是在反序列化过程的步骤11中的序列化规范第3.1节中指定的。如果cl不可序列化,则返回cl的无arg构造函数。如果找不到可访问的构造函数,或者类层次结构的格式不正确(例如,可序列化类没有超类(,则返回null。

您的第一个不可序列化超类是B,但是B没有arg构造函数,因为它的所有构造函数都有一个类型为Solution的合成参数。因此,找不到构造函数,反序列化失败。当您使BA可串行化时,它可以工作,因为newConstructorForSerialization将上升到Object(请参阅下面的循环(并使用其无参数构造函数。

public final Constructor<?> newConstructorForSerialization(Class<?> cl) {
Class<?> initCl = cl;
while (Serializable.class.isAssignableFrom(initCl)) {
Class<?> prev = initCl;
if ((initCl = initCl.getSuperclass()) == null ||
(!disableSerialConstructorChecks && !superHasAccessibleConstructor(prev))) {
return null;
}
}
Constructor<?> constructorToCall;
try {
constructorToCall = initCl.getDeclaredConstructor();
int mods = constructorToCall.getModifiers();
if ((mods & Modifier.PRIVATE) != 0 ||
((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
!packageEquals(cl, initCl))) {
return null;
}
} catch (NoSuchMethodException ex) {
return null;
}
return generateConstructor(cl, constructorToCall);
}

你能完全避免这样做吗?阅读这个问题的答案,似乎强烈反对像现在这样序列化内部实例(链接中的完整解释(。你很难做到这一点,但至少现在我们知道为什么会失败。

不需要父类的默认构造函数。使类A成为可序列化的类将起作用。您也可以从类C中删除序列化。

public class Solution implements Serializable {
public class A implements Serializable{
String name = "A";
public A(String name) {
this.name += name;
}
public A() {}
}
public class B extends A {
String name = "B";
public B(String name) {
super(name);
this.name += name;
}
public B() {}
}
public class C extends B {
String name;
public C(String name) {
super(name);
this.name = name;
}
}

}

最新更新