Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why default constructor is not called while deserialization process?

ObjectInputStream is = new ObjectInputStream(new FileInputStream("test.ser"));
TestClass tc = (TestClass)is.readObject();

I get the object of TestClass after deserialization but TestClass default constructor is not called. As per my understanding there are two ways to create object i.e either with new operator or TestClass.class.newInstance(). Both calls the default constructor.

Looks like deserialization process creates the object not with about two methods thats why default constructor is not called. Question is how deserialization creates the object ?

Another point is if TestClass extends BaseTestClass and BaseTestClass does not implements serialization , constructor of BaseTestClass is called but not TestClass. Why so ? I am sure there will be some logical reason behind it. But i am not getting it?

like image 760
M Sach Avatar asked Oct 26 '25 11:10

M Sach


1 Answers

It's worth reading Java Object Serialization Specification: 3 - Object Input Classes where readObject method is described in details along with step by step explanation.

How it works?

An instance of the class is allocated. The instance and its handle are added to the set of known objects.

The contents restored appropriately:

  1. For serializable objects, the no-arg constructor for the first non-serializable supertype is run.

    • For serializable classes, the fields are initialized to the default value appropriate for its type.

    • Then the fields of each class are restored by calling class-specific readObject methods, or if these are not defined, by calling the defaultReadObject method.

    • Note that field initializers and constructors are not executed for serializable classes during deserialization.

    • In the normal case, the version of the class that wrote the stream will be the same as the class reading the stream. In this case, all of the supertypes of the object in the stream will match the supertypes in the currently-loaded class.

    • If the version of the class that wrote the stream had different supertypes than the loaded class, the ObjectInputStream must be more careful about restoring or initializing the state of the differing classes.

    • It must step through the classes, matching the available data in the stream with the classes of the object being restored. Data for classes that occur in the stream, but do not occur in the object, is discarded.

    • For classes that occur in the object, but not in the stream, the class fields are set to default values by default serialization.

  2. For externalizable objects, the no-arg constructor for the class is run and then the readExternal method is called to restore the contents of the object.


Sample code to understand fist point For serializable objects, the no-arg constructor for the first non-serializable supertype is run.

Sample code;

class TestClass1 {
    public TestClass1() {
        System.out.println("TestClass1");
    }
}

class TestClass2 extends TestClass1 implements Serializable {
    public TestClass2() {
        System.out.println("TestClass2");
    }
}

public static void main(String[] args) throws Exception {
    System.out.println("Object construction via calling new keyword");
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("resources/dummy.dat"));
    out.writeObject(new TestClass2());

    System.out.println("Object construction via readObject method");
    ObjectInputStream is = new ObjectInputStream(new FileInputStream("resources/dummy.dat"));
    TestClass2 tc = (TestClass2) is.readObject();
}

output:

Object construction via calling new keyword
TestClass1
TestClass2

Object construction via readObject method
TestClass1
like image 86
Braj Avatar answered Oct 28 '25 23:10

Braj



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!