Thursday, May 19, 2016

Serialization with Inheritance

If Super class is Serializable:
If the superclass is Serializable than all its sub-classes will be serializable by default. No need to implement the serializable interface in subclass explicitly.

If Superclass is not Serializable but subclass is:
If the superclass is not Serializable than to serialize the subclass’ object we must implement the serializable interface in subclass explicitly. In this case, the superclass must have a no-argument constructor in it.

If the superclass is serializable but we don’t want the subclass to be serialized:
To prevent the subclass from being serialized we must implement writeObject() and readObject() method and need to throw NotSerializableException from these methods.

class Animal {
public String name;
}
class Dog extends Animal implements Serializable {
// the rest of the Dog code
}

Because Animal is NOT serializable, any state maintained in the Animal class,
even though the state variable is inherited by the Dog, isn't going to be restored
with the Dog when it's deserialized!

The reason is, the (unserialized) Animal part of the Dog is going to be reinitialized just as it would be if you were making a new Dog (as opposed to deserializing one).
That means all the things that happen to an object during construction, will happen—but only to the Animal parts of a Dog.

In other words, the instance variables from the Dog's class will be serialized and deserialized correctly, but the inherited variables from the non-serializable Animal superclass will come back with their default/initially assigned values rather than the values they had at the time of serialization.

If you are a serializable class, but your superclass is NOT serializable, then any
instance variables you INHERIT from that superclass will be reset to the values they
were given during the original construction of the object. This is because the non-serializable class constructor WILL run!

In fact, every constructor ABOVE the first non-serializable class constructor will
also run, no matter what, because once the first super constructor is invoked, (during
deserialization), it, of course, invokes its super constructor and so on up the inheritance
tree.


class Animal { // not serializable !
       int weight = 42;
}
class Dog extends Animal implements Serializable {
       String name;

       Dog(int w, String n) {
              weight = w; // inherited
              name = n; // not inherited
       }
}

class SuperNotSerial {
       public static void main(String[] args) {
              Dog d = new Dog(35, "Fido");
              System.out.println("before: " + d.name + " " + d.weight);
              try {
                     FileOutputStream fs = new FileOutputStream("testSer.ser");
                     ObjectOutputStream os = new ObjectOutputStream(fs);
                     os.writeObject(d);
                     os.close();
              } catch (Exception e) {
                     e.printStackTrace();
              }
              try {
                     FileInputStream fis = new FileInputStream("testSer.ser");
                     ObjectInputStream ois = new ObjectInputStream(fis);
                     /* it'll deserialize the name property of dog but not weight 
                     inherited from superclass,it runs the superclass constructor*/
                     d = (Dog) ois.readObject();
                     ois.close();
              } catch (Exception e) {
                     e.printStackTrace();
              }
              System.out.println("after: " + d.name + " " + d.weight);
       }
}

Output:
before: Fido 35
after: Fido 42


No comments:

Post a Comment