Apparently, the Java serialization mechanism somehow manages to instantiate the subclass using the superclass constructor. I wonder how this is possible?
Here is a test that demonstrates this:
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);
}
}
}
Conclusion:
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]
(You can try it in real time on Ideone ).
As you can see, the constructor A()is called during deserialization to create an instance B. Under the hood, this is called in ObjectStreamClass.newInstance(), and the instance is created by a call Constructor.newInstance(). In the debugger, the constructor consis Test$A():

After leaving the debugger, the created object finally returns from ObjectInputStream.readObject(...)and is sent without problems B.
, , , A() ( ) B.
, .