Thursday, 4 May 2017

Java Serialization and Deserialization Interview Questions with Example

Serialization and Deserialization Java Interview Questions OR
Serialization interview questions in Java OR
How are constructors called during serialization and deserialization OR
Why default constructor is not called while deserialization process.


In this post, we will see Serialization and Deserialization Interview Questions in Java.
How Serialization - Deserialization works in Java. Serialization - Deserialization example in Java. 

 
Java Serialization and Deserialization is important concept and most asked in interviews at beginners level.


See below diagram to get overview of Serialization and Deserialization process.


Question 1: How Deserialization works in Java? How are constructors called during serialization and deserialization? Deserialization process invokes constructor for creating object?


class Parent implements Serializable{
 public Parent(){
  System.out.println("Parent Constructor");
 }
}

class Child extends Parent{    
 public Child(){
  System.out.println("Child Constructor");
 }
}

public class MainClass {

 public static void main(String[] args){
  try {

   /****** SERIALIZATION ******/
   Child c = new Child();
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   ObjectOutputStream oos = new ObjectOutputStream(baos);

   System.out.println("Serializing Object...");
   oos.writeObject(c);
   oos.flush();
   baos.flush();
   oos.close();
   baos.close();

   /****** DE-SERIALIZATION ******/
   ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
   ObjectInputStream ois = new ObjectInputStream(bais);
   System.out.println("Deserializing Object...");
   Child deserializedChild = (Child)ois.readObject();

  } catch (Exception ex){
   ex.printStackTrace();
  }
 }

}
Output :
Parent Constructor
Child Constructor
Serializing Object...
Deserializing Object...


Explanation:
No constructor is called in Deserializing process. How this is possible? If the constructor is not called then how the new Child object "deserializedChild" is created. 
Now the question is "Is there a way to create object without calling constructor of a class?"

Let's answer all questions one by one. 

Java Deserializing process says, "For serializable objects, the no-arg constructor for the first non-serializable supertype is run."

Lets simplify above line, It means during deserialization process, JVM checks the inheritance class hierarchy of instance in process. 

It checks, if the Class instance in process has implemented Serializable interface, If yes, then JVM will check Parent class(If any) of the instance to see if Parent has implemented Serializable interface, If yes, then JVM continues to check all its Parents upwards till it encounters a class which doesn't implement Serializable interface. If all inheritance hierarchy of instance has implemented Serializable interface as one shown above then JVM will end up at default extended Object class which doesn't implemented Serializable interface. So it will create a instance of Object class by calling a default constructor of Object class.

So in above example, JVM will first check whether Child class has implemented Serializable interface, Yes, it has implemented(through Super class-Sub class hierarchy).
Now, JVM will check whether Child class parent that is Parent class has implemented Serializable interface, Yes, it has implemented. 
Now, JVM will check whether Parent class parent that is default Object class has implemented Serializable interface, No, it has not implemented, So JVM will stop further check.
It will create instance of Object class by invoking its default constructor and with the help of created instance, it creates instance of Parent and Child class using newConstructorForSerialization() method of ReflectionFactory class which internally create instance without invoking constructor of class.

So, In Deserialization process, Constructor of class may be invoked or may not be based on whether class has implemented Serializable interface or not.

Lets see one example and things will be more clear.
class A{
 private int a=10;
 public A(){
  System.out.println("A Constructor");
 }
 public int getA() {
  return a;
 }
 public void setA(int a) {
  this.a = a;
 }
}

class B extends A{
 private int b=15;
 public B(){
  System.out.println("B Constructor");
 }
 public int getB() {
  return b;
 }
 public void setB(int b) {
  this.b = b;
 }
}

class C extends B implements Serializable{
 private int c=25;
 public C(){
  System.out.println("C Constructor");
 }
 public int getC() {
  return c;
 }
 public void setC(int c) {
  this.c = c;
 }
}

class D extends C{
 private int d=30;
 public D(){
  System.out.println("D Constructor");
 }
 public int getD() {
  return d;
 }
 public void setD(int d) {
  this.d = d;
 }
}

public class MainClass {

 public static void main(String[] args){
  try {

   /****** SERIALIZATION ******/
   D d = new D();
   d.setA(100);
   d.setB(101);
   d.setC(102);
   d.setD(103);
   
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   ObjectOutputStream oos = new ObjectOutputStream(baos);

   System.out.println("Serializing Object...");
   oos.writeObject(d);
   oos.flush();
   baos.flush();
   oos.close();
   baos.close();

   /****** DE-SERIALIZATION ******/
   ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
   ObjectInputStream ois = new ObjectInputStream(bais);
   System.out.println("Deserializing Object...");
   D deserializedD = (D)ois.readObject();
   
   System.out.println(deserializedD.getA());
   System.out.println(deserializedD.getB());
   System.out.println(deserializedD.getC());
   System.out.println(deserializedD.getD());

  } catch (Exception ex){
   ex.printStackTrace();
  }
 }
}

 
Output:
A Constructor
B Constructor
C Constructor
D Constructor
Serializing Object...
Deserializing Object...
A Constructor
B Constructor
10
15
102
103
 

Constructor of A and B class is invoked and that is why data of class A and B is set by calling standard constructor whereas for class C and D data is set not by calling constructor but by the data which was present in serialized stream due to which it preserved 102 and 103 which was initialized before serialization.


Question 2: 
During deserialization process, it is said that the no-arg constructor for the first non-serializable supertype is run, what if that class doesn't has default constructor, is it a compile time problem or a run time exception?
 
class A{
 private int a=10;
 public A(){
  System.out.println("A Constructor");
 }
 public int getA() {
  return a;
 }
 public void setA(int a) {
  this.a = a;
 }
}

class B extends A{
 private int b=15;
 public B(int b){  //No default Constructor Present
  System.out.println("B Constructor");
 }
 public int getB() {
  return b;
 }
 public void setB(int b) {
  this.b = b;
 }
}

class C extends B implements Serializable{
 private int c=25;
 public C(){
  super(500);
  System.out.println("C Constructor");
 }
 public int getC() {
  return c;
 }
 public void setC(int c) {
  this.c = c;
 }
}

class D extends C{
 private int d=30;
 public D(){
  System.out.println("D Constructor");
 }
 public int getD() {
  return d;
 }
 public void setD(int d) {
  this.d = d;
 }
}

public class MainClass {

 public static void main(String[] args){
  try {

   /****** SERIALIZATION ******/
   D d = new D();
   d.setA(100);
   d.setB(101);
   d.setC(102);
   d.setD(103);
   
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   ObjectOutputStream oos = new ObjectOutputStream(baos);

   System.out.println("Serializing Object...");
   oos.writeObject(d);
   oos.flush();
   baos.flush();
   oos.close();
   baos.close();

   /****** DE-SERIALIZATION ******/
   ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
   ObjectInputStream ois = new ObjectInputStream(bais);
   System.out.println("Deserializing Object...");
   D deserializedD = (D)ois.readObject();
   
   System.out.println(deserializedD.getA());
   System.out.println(deserializedD.getB());
   System.out.println(deserializedD.getC());
   System.out.println(deserializedD.getD());

  } catch (Exception ex){
   ex.printStackTrace();
  }
 }

}
Output :
A Constructor
B Constructor
C Constructor
D Constructor
Serializing Object...
Deserializing Object...
java.io.InvalidClassException: D; no valid constructor


Explanation:
First class in the inheritance hierarchy which doesn't implement Serializable interface is B and it doesn't has Default Constructor in our example.
So, from compilation standpoint there is no issue and things works fine. 
During runtime when JVM tries to create instance of class B at that time it will try to call default constructor of class B and it will unable to find due to which it throws exception at Runtime.

Below is perfectly valid deserialization scenario and from below example you will come to know the actual meaning of line which says, "During deserialization, the no-arg constructor for the first non-serializable class should be present"

In below example, the first class which is non-serializable is B, which is having default constructor but its parent that is A is not having default constructor and that is fine because JVM only need no-arg constructor of only first non-serializable class.
 
class A{
 private int a=10;
 public A(int a){ // No default constructor
  System.out.println("A Constructor");
 }
 public int getA() {
  return a;
 }
 public void setA(int a) {
  this.a = a;
 }
}

class B extends A{
 private int b=15;
 public B(){
  super(500);  
  System.out.println("B Constructor");
 }
 public int getB() {
  return b;
 }
 public void setB(int b) {
  this.b = b;
 }
}

class C extends B implements Serializable{
 private int c=25;
 public C(){
  System.out.println("C Constructor");
 }
 public int getC() {
  return c;
 }
 public void setC(int c) {
  this.c = c;
 }
}

class D extends C{
 private int d=30;
 public D(){
  System.out.println("D Constructor");
 }
 public int getD() {
  return d;
 }
 public void setD(int d) {
  this.d = d;
 }
}

public class MainClass {

 public static void main(String[] args){
  try {

   /****** SERIALIZATION ******/
   D d = new D();
   d.setA(100);
   d.setB(101);
   d.setC(102);
   d.setD(103);
   
   ByteArrayOutputStream baos = new ByteArrayOutputStream();
   ObjectOutputStream oos = new ObjectOutputStream(baos);

   System.out.println("Serializing Object...");
   oos.writeObject(d);
   oos.flush();
   baos.flush();
   oos.close();
   baos.close();

   /****** DE-SERIALIZATION ******/
   ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
   ObjectInputStream ois = new ObjectInputStream(bais);
   System.out.println("Deserializing Object...");
   D deserializedD = (D)ois.readObject();
   
   System.out.println(deserializedD.getA());
   System.out.println(deserializedD.getB());
   System.out.println(deserializedD.getC());
   System.out.println(deserializedD.getD());

  } catch (Exception ex){
   ex.printStackTrace();
  }
 }

}

Output:
A Constructor
B Constructor
C Constructor
D Constructor
Serializing Object...
Deserializing Object...
A Constructor
B Constructor
10
15
102
103



You may also like to see


Important Java Multithreading Interview Questions-Answers

How is ambiguous overloaded method call resolved in java?

Exception Handling Interview Question-Answer

Type Casting Interview Questions In Java

Method Overriding rules in Java

Java Interface interview questions and answers

Enjoy !!!! 

If you find any issue in post or face any error while implementing, Please comment.

No comments:

Post a Comment