Java Serialization Tutorial

Serialization in Java is very important topic. In most of distributed applications objects needs to be serialized. At the same time if you don't implement Serialization properly it may lead to many issues related to performance and code maintainability. In this Serialization Tutorial we are covering Serialization in detail with example.

What is Serialization?

Serialization is the process of writing the 'state of an object' to an external medium, such as file or network in order to retrieve it later. The reverse of serialization is called deserialization i.e. the process of reading the information from external medium and then reconstruction the object back again.

Why we need Serialization?

There can be multiple reasons for Serialization some of them explained below: Suppose you have an object like below:
   Person obj = new Person();
Now if you want this object to send over network to another machine (say Machine B), what will you do? you send obj to machine B. But obj is just an address in the heap of original machine and that does not make any sense at machine B, because there might be completely something else in machine B at that address. So if we need to send the object to some other machine (or other JVM), we need to send its state by writing it on a stream.
Another reason can be you want to save current state of object so it can be used later. In that case you Serialize the object to your file system.

Serializable Interface

Any class whose objects you want to searialize must implement Serializable interface. java.io.Serializable is a marker interface and don't have any methods or fields, it just serves the purpose to declare that the class is Serializable. If you try to serialize objects of a class which is not Serializable it will throw java.io.Serializable exception.
All subclasses of a Serializable class are also Serializable by default.
If class A is serializable but its super class 'B' is not Serializable. Now when you serialize the objects of 'A' it wont give any exception but the variables directly defined in B won't be serialized, and when you deserialize the object the fields of B would be initialized by calling default constructor of B class. That means the no-arg constructor of super class (B) must be accessible from child class (A), otherwise it give error at runtime.

How to Serialize an object : Example program code

The steps to serialize an objects to a file are mentioned below:
  1. The class must implement Serializable interface.
  2. Create FileOutputStream object(fos), by passing file name.
  3. Create ObjectOutputStream object(oos), by passing fos as parameter.
  4. Invoke fos.writeObject(Object obj) method by passing the object you are serializing.
The example program is given below. It has 2 files 'Employee.java' and 'SerializationDemo.java'. The objects of Employee class would be serialized to 'myfile' file.

package com.bamals.serialization; import java.io.Serializable; public class Employee implements Serializable { private static final long serialVersionUID = -1209632977206113443L; private int salary; private String name; public Employee(int salary, String name) { this.salary = salary; this.name = name; } public int getSalary() { return salary; } public void setSalary(int salary) { this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Employee [salary=" + salary + ", name=" + name + "]"; } }

package com.bamals.serialization; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.IOException; public class SerializationDemo { /* Code to serialize the object. */ void serializeObject(Employee obj) throws IOException { FileOutputStream fos = new FileOutputStream("myfile"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(obj); oos.close(); } /* code to de-serialize the object. */ Employee deserializeObject() throws IOException, ClassNotFoundException{ FileInputStream fis = new FileInputStream("myfile"); ObjectInputStream ois = new ObjectInputStream(fis); Employee obj = (Employee) ois.readObject(); ois.close(); return obj; } public static void main(String args[]){ SerializationDemo demo = new SerializationDemo(); try { Employee obj = new Employee(1000, "Amit"); System.out.println("Object before Serialization - " + obj); demo.serializeObject(obj); obj.setName("Sameer"); obj.setSalary(2000); System.out.println("Changed Object after Serialization - "+obj); } catch (IOException e) { e.getMessage(); } System.out.println("----- Deserializing the object below -----"); try { Employee emp = demo.deserializeObject(); System.out.println("Deserialized object - " + emp); } catch (ClassNotFoundException e) { System.out.println(e); } catch (IOException e) { System.out.println(e); } } }

Object before Serialization - Employee [salary=1000, name=Amit] Changed Object after Serialization - Employee [salary=2000, name=Sameer] ----- Deserializing the object below ----- Deserialized object - Employee [salary=1000, name=Amit]

serialVersionUID

It is strongly recommended that every serializable class explicitly declare a private field serialVersionUID.
If you explicitly do not declare it, then at runtime JVM will calcuate a default value of serialVersionUID based on what fields/methods are declared in the class etc and it makes your class backward incompatible for Serialization. Any modification to the class in future will result in InvalidClassExceptions during deserialization.

How object is reconstructed during deserialization

When object is reconstructed during deserialization, constructor of the Serializable class is not invoked. Instead it invokes the no-arg constructor of its superclass. If superclass is also Serializable it checks further superclass until it finds a class which is not Serializable and no-arg constructor of that class is invoked. Once the new object is created using superclass constructor, state of Serializable objects are restored by reading them from ObjectInputStream.
Notice the new object is created during deserialization even though constructor of Serializable class is not invoked.

Important points to note about Serialization and Deserialization

  • You can mark some fields of the class as transient if you don't want them to be serialized.
  • Upon deserialization the transient fields will have default value (which is null for Strings).
  • Since static is part of class and not part of object, so static variables are not serialized.
  • While Serialization the whole object graphs is traversed and it tries to Serialze all the objects that it encounter. So if an objects is encountered that is not serializable, then NotSerializableException will be thrown and will identify the class of the non-serializable object. To avoid this you can mark the reference variable that hold this object as transient.