显然,Java序列化机制以某种方式设法使用超类构造函数创建子类的实例。我想知道,怎么可能?
这里有一个test来证明这一点:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.text.MessageFormat;
public class Test {
public static class A {
public final int a;
public A() {
this.a = 0;
System.out.println(
MessageFormat.format(
"new A() constructor is called to create an instance of {0}.",
getClass().getName()));
}
public A(int a) {
this.a = a;
System.out.println(
MessageFormat.format(
"new A(int) constructor is called to create an instance of {0}.",
getClass().getName()));
}
}
public static class B extends A implements Serializable {
public final int b;
public B(int a, int b) {
super(a);
this.b = b;
System.out.println(
MessageFormat.format(
"new B(int, int) constructor is called to create an instance of {0}.",
getClass().getName()));
}
@Override
public String toString() {
return "B [a=" + a + ", b=" + b + "]";
}
}
public static void main(String[] args) throws Exception {
B b1 = new B(10,20);
System.out.println(b1);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try(ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(b1);
}
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
B b2 = (B)ois.readObject();
System.out.println(b2);
}
}
}
输出:
new A(int) constructor is called to create an instance of Test$B.
new B(int, int) constructor is called to create an instance of Test$B.
B [a=10, b=20]
new A() constructor is called to create an instance of Test$B.
B [a=0, b=20]
(你可以try it out live on Ideone)。
如您所见,在反序列化期间调用A()
构造函数以生成B
的实例。在引擎盖下,这在ObjectStreamClass.newInstance()
中调用,实例由Constructor.newInstance()
调用创建。在调试器中,构造函数cons
为Test$A()
:
退出调试器后,最终会从ObjectInputStream.readObject(...)
返回创建的对象,并且它会毫无问题地投放到B
。
因此,如果我没有弄错的话,似乎使用A()
构造函数(通过反射)来创建B
的实例。
我想知道这怎么可能。
答案 0 :(得分:2)
我怀疑构造函数cons
一定有问题。我找到了A
的普通构造函数更改为serializable constructor
B
的位置。
首先,我查看了cons
首次设置的位置。在序列化的情况下,这是ObjectStreamClass
:
if (externalizable) {
cons = getExternalizableConstructor(cl);
} else {
cons = getSerializableConstructor(cl); //here
...
所以我介入并找到ObjectStreamClass.getSerializableConstructor
:
Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
...
cons = reflFactory.newConstructorForSerialization(cl, cons); //this does change
cons.setAccessible(true);
return cons;
将调试监视放在cons.newInstance()
A
。B
。这意味着用于序列化的构造函数不是A
的普通构造函数,而是用于序列化的修改构造函数,它适用于最终类。
答案 1 :(得分:0)
Serializable
的第一个父项的no args构造函数。虽然它不会在此构造函数中创建类的实例。如果您的父类是Serializable
,则根本没有构造函数调用。