Sunday, November 24, 2019

Serialization Interview Questions

What is Serialization in java?
Serialization is process of converting object into byte stream.
 Serialized object (byte stream) can be:
 >Transferred over network.
 >Persisted/saved into file.
 >Persisted/saved into database.
Once, object have have been transferred over network or persisted in file or in database, we could deserialize the object and retain its state as it is in which it was serialized

How do we Serialize object, write a program to serialize and deSerialize object and persist it in file ?
In order to serialize object our class needs to implement java.io.Serializable interface. Serializable interface is Marker interface i.e. it does not have any methods of its own, but it tells Jvm that object has to converted into byte stream.

SERIALIZATION>
Create object of ObjectOutput and give it’s reference variable name oout and call writeObject() method and pass our employee object as parameter [oout.writeObject(object1) ]


OutputStream fout = new FileOutputStream("ser.txt");
ObjectOutput oout = new ObjectOutputStream(fout);
System.out.println("Serialization process has started, serializing employee objects...");
oout.writeObject(object1);


DESERIALIZATION>
Create object of ObjectInput and give it’s reference variable name oin and call readObject() method [oin.readObject() ]

InputStream fin=new FileInputStream("ser.txt");
ObjectInput oin=new ObjectInputStream(fin);
System.out.println("DeSerialization process has started, displaying employee objects...");
Employee emp;
emp=(Employee)oin.readObject();


Difference between Externalizable and Serialization interface (Important)?


Methods
It is a marker interface it doesn’t have any method.
It’s not a marker interface.
It has method’s called writeExternal() and readExternal()
Default Serialization process
YES, Serializable provides its own default serialization process, we just need to implement Serializable interface.
NO, we need to override writeExternal() and readExternal() for serialization process to happen.
Customize serialization process
We can customize default serialization process by defining following methods in our class >readObject() and writeObject()  
Note: We are not overriding these methods, we are defining them in our class.
Serialization process is completely customized
We need to override Externalizable interface’s writeExternal() and readExternal() methods.
Control over Serialization
It provides less control over Serialization as it’s not mandatory to define readObject() and writeObject() methods.
Externalizable provides you great control over serialization process as it is important to override  writeExternal() and readExternal() methods.
Constructor call during deSerialization
Constructor is not called during deSerialization.
Constructor is called during deSerialization.


How can you customize Serialization and DeSerialization process when you have implemented Serializable interface ?
Answer.  Here comes the quite challenging question, where you could prove how strong your Serialization concepts are.We can customize Serialization process by defining writeObject()  method & DeSerialization process by defining readObject() method.

Let’s customize Serialization process by defining writeObject()  method :

      private void writeObject(ObjectOutputStream os) {
           System.out.println("In, writeObject() method.");   
           try {
                  os.writeInt(this.id);
                  os.writeObject(this.name);
           } catch (Exception e) {
                  e.printStackTrace();
           }
    }
We have serialized id and name manually by writing them in file.
 
Let’s customize DeSerialization process by defining readObject()  method :

    private void readObject(ObjectInputStream ois) {
           System.out.println("In, readObject() method.");
           try {
                  id=ois.readInt();
                  name=(String)ois.readObject();
           } catch (Exception e) {
                  e.printStackTrace();
           }
    }

We have DeSerialized id and name manually by reading them from file.

How can you avoid certain member variables of class from getting Serialized?

Answer. Mark member variables as static or transient, and those member variables will no more be a part of Serialization.

What is serialVersionUID?
The serialization at runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization.

What are compatible and incompatible changes in Serialization process?
Compatible Changes :  Compatible changes are those changes which does not affect deSerialization process even if class was updated after being serialized (provided serialVersionUID has been declared)
 Adding new fields - We can add new member variables in class.
 Adding writeObject()/readObject()  methods - We may add these methods to customize serialization process.
 Removing writeObject()/readObject() methods - We may remove these methods and then default customization process will be used.
 Changing access modifier of a field - The change to access modifiers i.e. public, default, protected, and private have no effect on the ability of serialization to assign values to the fields.
 Changing a field from static to non static OR changing transient filed to non transient field. - it’s like addition of fields.

InCompatible Changes :  InCompatible changes are those changes which affect deSerialization process if class was updated after being serialized (provided serialVersionUID has been declared)
 Deletion of fields.
 Changing a nonstatic field to static or  non transient field to transient field. - it’s equal to deletion of fields.

 Modifying the writeObject() / readObject() method - we must not modify these method, though adding or removing them completely is compatible change.

What if Serialization is not available, is any any other alternative way to transfer object over network?
>We can can convert JSON to transfer the object. JSON is helpful in stringifying and de stringifying object.
>Hibernate (ORM tool) helps in persisting object as it in database and later we can read persisted object.
>We can convert object into XML (as done in web services) and transfer object over network.

Why static member variables are not part of java serialization process (Important)?
Answer. Serialization is applicable on objects or primitive data types only, but static members are class level variables, therefore, different object’s of same class have same value for static member.
So, serializing static member will consume unnecessary space and time.
Also, if modification is made in static member by any of the object, it won’t be in sync with other serialized object’s value.

What is significance of transient variables?
Answer. Serialization is not applicable on transient variables (it helps in saving time and space during Serialization process), we must mark all rarely used variables as transient. We can initialize transient variables during deSerialization by customizing deSerialization process.

What will happen if one the member of class does not implement Serializable interface (Important)?
Answer. This is classy question which will check your in depth knowledge of Serialization concepts. If any of the member does not implement Serializable than  NotSerializableException is thrown.

What will happen if we have used List, Set and Map as member of class?
Answer. This question which will check your in depth knowledge of Serialization and Java Api’s. ArrayList, HashSet and HashMap implements Serializable interface, so if we will use them as member of class they will get Serialized and DeSerialized as well.

Are primitive types part of serialization process in java?
Yes, primitive types are part of serialization process.

Is constructor of class called during DeSerialization process?
Answer. This question which will check your in depth knowledge of Serialization and constructor chaining concepts. It depends on whether our object has implemented Serializable or Externalizable.
If Serializable has been implemented - constructor is not called during DeSerialization process.
But, if Externalizable has been implemented - constructor is called during DeSerialization process.

What values will int and Integer will be initialized to during DeSerialization process if they were not part of Serialization?
Answer.  int will be initialized to 0 and Integer will be initialized to null during DeSerialization (if they were not part of Serialization process).

How you can avoid Deserialization process creating another instance of Singleton class (Important)?
Answer. This is another classy and very important question which will check your in depth knowledge of Serialization and Singleton concepts. I’ll prefer you must understand this concept in detail. We can simply use readResove() method to return same instance of class, rather than creating a new one.

Defining readResolve() method ensures that we don't break singleton pattern during DeSerialization process.
   
  private Object readResolve() throws ObjectStreamException {
       return INSTANCE;
  }

Also define readObject() method, rather than creating new instance, assign current object to INSTANCE like done below :
  private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException{
        ois.defaultReadObject();
        synchronized (SingletonClass.class) {
         if (INSTANCE == null) {
               INSTANCE = this;
         }
        }
  }

Can you Serialize Singleton class such that object returned by Deserialization process  is in same state as it was during Serialization time (regardless of any change made to it after Serialization)  (Important)?
Answer. It’s another very important question which will be important in testing your Serialization and Singleton related concepts, you must try to understand the concept and question in detail.
YES, we can Serialize Singleton class such that object returned by Deserialization process is in same state as it was during Serialization time (regardless of any change made to it after Serialization)


Defining readResolve() method ensures that we don't break singleton pattern during DeSerialization process.
   
  private Object readResolve() throws ObjectStreamException {
       return INSTANCE;
  }

Also define readObject() method, rather than creating new instance, assign current object to INSTANCE like done below :
  private void readObject(ObjectInputStream ois) throws IOException,ClassNotFoundException{
        ois.defaultReadObject();
        synchronized (SingletonClass.class) {
         if (INSTANCE == null) {
               INSTANCE = this;
         }
        }
  }

Purpose of serializing Singleton class OR  purpose of saving singleton state?
Answer. Let’s take example of our laptop, daily eod we need to shut it down, but rather than shutting it down hibernate (save state of  laptop) is better option because it enables us to resume at same point where we leaved it, like wise serializing singleton OR saving state of Singleton can be very handy.

How can subclass avoid Serialization if its superClass has implemented Serialization interface ?
If superClass has implemented Serializable that means subclass is also Serializable (as subclass always inherits all features from its parent class), for avoiding Serialization in sub-class we can define writeObject() method and throw NotSerializableException().
private void writeObject(ObjectOutputStream os) throws NotSerializableException {
        throw new NotSerializableException("This class cannot be Serialized");
}

Key Points :

Even though serialVersionUID is a static field, it gets serialized along with the object. This is one exception to the general serialization rule that, “static fields are not serialized”.

serialVersionUID is a must in serialization process. But it is optional for the developer to add it in java source file. If you are not going to add it in java source file, serialization runtime will generate a serialVersionUID and associate it with the class. The serialized object will contain this serialVersionUID along with other data.

The serialVersionUID for dynamic proxy classes and enum types always have the value 0L
transient and static fields are ignored in serialization. After deserialization transient fields and non-final static fields will be null.
final and static fields still have values since they are part of the class data.

ObjectOutputStream.writeObject(obj) and ObjectInputStream.readObject() are used in serialization and deserialization.
During serialization, we need to handle IOException; during deserialization, we need to handle IOException and ClassNotFoundException. So the deserialized class type must be in the classpath.
Uninitialized non-serializable, non-transient instance fields are tolerated.
When adding “private Thread th;“, no error in serializable. However, “private Thread threadClass = new Thread();” will cause exception:

Console
Exception in thread "main" java.io.NotSerializableException: java.lang.Thread
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at com.howtodoinjava.demo.serialization.DemoClass.writeOut(DemoClass.java:42)
at com.howtodoinjava.demo.serialization.DemoClass.main(DemoClass.java:27)
Serialization and deserialization can be used for copying and cloning objects. It is slower than regular clone, but can produce a deep copy very easily.
If I need to serialize a Serializable class Employee, but one of its super classes is not Serializable, can Employee class still be serialized and deserialized? The answer is yes, provided that the non-serializable super-class has a no-arg constructor, which is invoked at deserialization to initialize that super-class.
We must be careful while modifying a class implementing java.io.Serializable. If class does not contain a serialVersionUID field, its serialVersionUID will be automatically generated by the compiler.
Different compilers, or different versions of the same compiler, will generate potentially different values.


How serialVersionUID is generated?
serialVersionUID is a 64-bit hash of the class name, interface class names, methods and fields. Serialization runtime generates a serialVersionUID if you do not add one in source.

Computation of serialVersionUID is based on not only fields, but also on other aspect of the class like implement clause, constructors, etc. So the best practice is to explicitly declare a serialVersionUID field to maintain backward compatibility. If we need to modify the serializable class substantially and expect it to be incompatible with previous versions, then we need to increment serialVersionUID to avoid mixing different versions.



No comments:

Post a Comment