In this tutorial, we gonna discuss What is Java Serialization? Example of serialization in java, Java Transient Keyword with Example, Object Graph in Serialization with sample program, etc. However, we have shared detailed information about Java Serialization Interface. The concepts that relate to Serialization in Java are provided here in the direct links with sample programs for a better understanding of the topic.
This Tutorial on Serialization in Java Consists of:
- Java Serialization
- Java Deserialization
- java.io.Serializable interface
- Example of Java Serialization
- Java Transient Keyword
- Example of Transient Keyword in Java
- Object Graph in Serialization
- Example of Object Graph in Serialization:
- Customized Serialization in Java
- Need for Customized Serialization in Java
- Example of Customized Serialization
- Java Serialization with Inheritance (IS-A Relationship)
- Externalizable in Java
- Java Externalizable Interface Methods
- Externalization Example in Java
- Serialization vs Externalization in Java
- What is SerialVersionUID in Java?
- Example of SerialVersionUID
Java Serialization
Serialization in Java is a technique of converting the state of an object into a byte stream. By using FileOutputStream and ObjectOutputStream classes we can achieve Serialization in Java. The ObjectOutputStream takes an object and converts it into binary data and FileOutputStream is used to write the binary data into a file. The writeObject() method of ObjectOutputStream is used to serialize our object.
Java Deserialization
Deserialization in Java is a mechanism of rebuilding the object from a byte stream or we can say that it is a reverse process of serialization. By using FileInputStream and ObjectInputStream classes we can achieve Deserialization in Java. The FileInputStream is used to read binary data from a file and ObjectInputStream is responsible for reading objects from a stream. The readObject() method of ObjectInputStream is used to deserialize our object.
Do Check:
java.io.Serializable Interface
A marker interface with no data member and method is known as Serializable. It is used to “mark” Java classes so that the objects of these classes may get a specific capability. The Cloneable and Remote are also marker interfaces. It needs to be executed by the class whose object you want to persist.
By default, the String class and all Wrapper classes implement the java.io.Serializable interface. Check out the below sample program on java.io.Serializable Interface and understand efficiently.
import java.io.Serializable; public class Student implements Serializable { int id; String name; public Student(int id, String name) { this.id = id; this.name = name; } }
Example of Java Serialization
The following program illustrates how to use serialization and deserialization in java. We can serialize only serializable objects. An object is said to be serializable if and only if a corresponding class implements the Serializable interface. The serializable interface present in a java.io package doesn’t contain any method. It is a marker interface. If we are trying to serialize a non-serializable object then we will get a runtime exception saying NotSerializableException.
import java.io.*; class Example implements Serializable { int a = 10; int b = 20; } class SerializationDemo { public static void main(String args []) throws Exception { Example obj1 = new Example(); // Serialization FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); System.out.println("Serialization Done!"); // Deserialization FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserialize our object Example obj2 = (Example) ois.readObject(); fis.close(); ois.close(); System.out.println("The value of a is: " + obj2.a); System.out.println("The value of b is: " + obj2.b); } }
Output:
Serialization Done! The value of a is: 10 The value of b is: 20
Java Transient Keyword
Transient is a keyword in Java that is used in Serialization. It is applicable only for variables. At the time of serialization if you don’t want to serialize the value of a particular object for security concern then we should go for the transient keyword in Java.
At the time of serialization when we declared a variable as transient JVM ignore the original value of a transient variable and set a default value to the file. Hence we can say that transient means not to serialize.
Example of Transient Keyword in Java
In this example, we have created two variables name and password. The password variable of an example class is declared as transient, so its values will not be serialized. Therefore JVM ignores the original value of a transient variable and sets a default value to the file.
import java.io.*; class Example implements Serializable { String name = "Amit"; // declared variable as transient transient int password = 12345; } class SerializationDemo { public static void main(String args []) throws Exception { Example obj1 = new Example(); // Serialization FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); System.out.println("Serialization Done!"); // Deserialization FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserialize our object Example obj2 = (Example)ois.readObject(); fis.close(); ois.close(); System.out.println("The User name is: ", + obj2.name); System.out.println("User password is: ", + obj2.password); } }
Output:
Serialization Done! The user name is: Amit User password is: 0
Object Graph in Serialization
Whenever we are serializing an object the set of all objects that contain the reference from that object will be serialized automatically. This group of a set is known as Object Graph. In Object Graph every object should be serializable. If at least one object is non-serializable then we will get a runtime exception saying NotSerializableException. Let’s understand this with an example.
Example of Object Graph in Serialization:
In this example, whenever we are serializing Serialize1 class objects automatically Serialize2 and Serialize3 class objects will be serialized, because these are the part of the object graph of Serialize1 object. Among Serialize1, Serialize2, and Serialize3 class if at least one object is not serializable then we will get a runtime exception.
import java.io.*; class Serialize1 implements Serializable { // class Serialize1 contains refrence to // object of class Serialize2 Serialize2 s2= new Serialize2(); } class Serialize2 implements Serializable { // class Serialize2 contains refrence to // object of class Serialize3 Serialize3 s3= new Serialize3(); } // A refrence of this class present // in class Serialize2 class Serialize3 implements Serializable { int a = 10; int b = 20; } class SerializationDemo { public static void main(String args []) throws Exception { //creating an object of class Serialize1 Serialize1 s1 =new Serialize1(); FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for serialize our object oos.writeObject(s1); fos.close(); oos.close(); System.out.println("Serialization Done!"); // Deserialization FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserialize our object Serialize1 sbj = (Serialize1)ois.readObject(); fis.close(); ois.close(); // Printing the value of a and b after serialization System.out.println(" The value of a after deserialization is: " + sbj.s2.s3.a); System.out.println(" The value of b after deserialization is: " + sbj.s2.s3.b); } }
Output:
Serialization Done! The value of a after deserialization is: 10 The value of b after deserialization is: 20
Customized Serialization in Java
In the normal Serialization, everything takes care of by the JVM so that the programmer roles are very very less. Sometimes we may not satisfy with default Serialization then we should go for Customized Serialization in Java.
Need for Customized Serialization in Java
In default Serialization, because of the transient keyword, there may be a chance of loss of information to recover this loss of information then we should go for Customized Serialization in Java.
Let’s take a simple example to understand this, In this example before Serialization Example, the class object can provide a proper username and password. But after the De-Serialization Example class object can provide the only username not password this is due to the transient keyword.
import java.io.*; class Account implements Serializable{ String username = "Amit"; transient int pwd = 12345; } class CustomizedDemo{ public static void main(String args[])throws Exception{ Account a1 = new Account(); System.out.println("Values before serialization"); System.out.println("User name is: " +a1.username); System.out.println("User password is: " +a1.pwd); //serialization process FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(a1); //Deserialization process. FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Account a2 = (Account)ois.readObject(); System.out.println("Values after Deserialization"); System.out.println("User name is: " +a2.username); System.out.println("User password is: " +a2.pwd); } }
Output:
Values before serialization User name is: Amit User password is: 12345 Values after Deserialization User name is: Amit User password is: 0
Example of Customized Serialization
We can implement Customized Serialization in Java by using the following two methods:
1. private void writeObject(ObjectOutputStream oos) throws Exception: This method will be executed automatically at the time of object Serialization. If you have to perform any activity during Serialization, it must be defined only in this method.
2. private void readObject(ObjectInputStream ois) throws Exception: This method will be executed automatically at the time of object deserialization. If you have to perform any activity during deserialization, it must be defined only in this method. The above methods are also known as the Callback methods because these methods will be executed automatically by the JVM. While performing Customized Serialization, we have to define the above two methods in that class.
import java.io.*; class Example implements Serializable { String name = "Amit"; // declared variable as transient transient String password = "java"; private void writeObject(ObjectOutputStream oos) throws Exception { // to perform default serialization of Example object oos.defaultWriteObject(); // encrypted password String epwd = "123"+password; // To write encrypted password to the file oos.writeObject(epwd); } private void readObject(ObjectInputStream ois) throws Exception { // to perform default deserialization of Example object ois.defaultReadObject(); // Reading encrypted password String epwd = (String)ois.readObject(); // perform decryption and assign decrypted // password in to the original password password = epwd.substring(3); } } class CustomizedDemo { public static void main(String args []) throws Exception { Example obj1 = new Example(); // printing username and password // before Serialization System.out.println("Before serialization"); System.out.println("The user name is: " +obj1.name); System.out.println("The password is: " +obj1.password); // Serialization FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); // Deserialization FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserializing our object Example obj2 = (Example)ois.readObject(); fis.close(); ois.close(); System.out.println("After Deserialization"); System.out.println("User name is: " + obj2.name); System.out.println("User password is: " + obj2.password); } }
Output:
Values before serialization User name is: Amit User password is: java Values after Deserialization User name is: Amit User password is: java
To understand the above example see in the image given below:
Java Serialization with Inheritance (IS-A Relationship)
Serialization in Java is a technique of converting the state of an object into a byte stream. Whereasdeserialization in Java is a mechanism of rebuilding the object from a byte stream or we can say that it is a reverse process of serialization. Here we have discussed two cases of Serialization concerning inheritance.
Case1- If a parent class is serializable but child class is not serializable:
If the parent class is serializable then by default every child class is serializable. You won’t need to implement a serializable interface in the child class. Hence, even though the child class doesn’t implement serializable if the parent class implement serializable then we can serialize the child class object. Let’s understand this with an example.
import java.io.*; // parent class implements // serializable interface. class A implements Serializable { int a = 10; } // child class doesn't implement // serializable interface. class B extends A { int b = 20; } class SerializationDemo { public static void main(String args []) throws Exception { B obj1 = new B(); System.out.println("Values before serialization"); System.out.println("The value of A is: " +obj1.a); System.out.println("The value of B is: " +obj1.b); //Serialization. FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); //Deserialization FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserializing our object B obj2 = (B)ois.readObject(); fis.close(); ois.close(); System.out.println("Values after Deserialization"); System.out.println("The value of A after deserialization is: " +obj2.a); System.out.println("The value of B after deserialization is:" +obj2.b); } }
Output:
Values before serialization The value of a is: 10 The value of b is: 20 Values after Deserialization The value of a after deserialization is: 10 The value of b after deserialization is: 10
Case 2- If a parent class is not serializable but a child class is serializable:
Even though a parent class doesn’t implement the Serializable interface, we can serialize the child class object if the child class itself implements the serializable interface. So we can say that to serialize child class objects, parent class does not need to be serialized. But now a question arises what happens with the parent class instances during Serialization in this case. Let’s understand this with the procedure given below:
1. At the time of Serialization, if any instance variable inheriting from a non-serializable parent class then JVM ignores its original value and saves the default value to the file.
2. At the time of deserialization, if any parent class is non-serializable then JVM will execute instance control flow in that non-serializable parent class. To execute instance control flow in a non-serializable parent class, JVM will always invoke a no-argument constructor (default constructor) of that class. Hence every non-serializable parent class must contain a no-argument constructor (default constructor), otherwise, we will get a runtime exception.
import java.io.*; //parent class doesn't implements //serializable interface. class A { int a = 10; //default constructor public A() { System.out.println("A's class constructor is called!"); } } //child class implements //serializable interface. class B extends A implements Serializable { int b = 20; //default constructor public B() { System.out.println("B's class constructor is called!"); } } class SerializationDemo { public static void main(String args []) throws Exception { B obj1 = new B(); obj1.a = 777; obj1.b = 888; System.out.println("The value of A is: " +obj1.a); System.out.println("The value of B is: " +obj1.b); //serialization process. FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); //Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); System.out.println("Serialization Done!"); System.out.println("De-serialization started!"); //Deserialization process. FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); //Method for deserializing our object B obj2 = (B)ois.readObject(); fis.close(); ois.close(); System.out.println("The value of A after deserialization is: " + obj2.a); System.out.println("The value of B after deserialization is: " + obj2.b); } }
Output:
A's class constructor is called! B's class constructor is called! The value of a is: 777 The value of b is: 888 Serialization Done! De-serialization started! A's class constructor is called! The value of a after deserialization is: 10 The value of b after deserialization is: 888
Externalizable in Java
In Serialization total object is saved to the file and it is not possible to save part of an object which creates a performance problem. To overcome this problem we should go to Externalization in Java. The main advantage of Externalization over Serialization is we can save either the total object or part of an object so that the relative performance will be improved.
An object is said to be externalizable if and only if a corresponding class implements the Externalizable interface. Externalizable is an interface that is present in java.io. package and it is the child interface of Serializable.
Java Externalizable Interface Methods
The Externalizable interface contains two methods.
1. public void writeExternal(ObjectOutput out) throws IOException:
This method will be executed automatically at the time of object Serialization. In this method, we have to write the code to save the required variables to a file.
2. public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException:
This method will be executed automatically at the time of object deserialization. In this method, we have to write the code to read the required variables from a file and assign them to the current object.
At the time of deserialization, JVM will create a separate new object by executing the default constructor on that object readExternal() method will be executed. Hence if a class implements an Externalizable interface then it should be compulsory for that class to contain a no-arg constructor (default constructor). Otherwise, we will get a runtime exception saying InvalidClassException.
Externalization Example in Java
Case 1: When the class doesn’t contain a no-arg constructor (default constructor). It will give InvalidClassException
import java.io.*; class Student implements Externalizable { String name; int id; String address; // parameterized constructor public Student(String name, int id, String address) { this.name= name; this.id = id; this.address = address; } public void writeExternal(ObjectOutput out) throws IOException { // variables saved into the file. out.writeObject(name); out.writeInt(id); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // Read the variables from a file name = (String)in.readObject(); id = in.readInt(); } } public class ExternalizationDemo { public static void main(String args []) throws Exception { Student obj1 = new Student("Amit", 101, "India"); // Serialize the Student FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); // deserialize the Student FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserializing our object Student obj2 = (Student) ois.readObject(); fis.close(); ois.close(); System.out.println("The student name is:" +obj2.name); System.out.println("The student Id is:" +obj2.id); System.out.println("The student address is:" +obj2.address); } }
Output:
Case 2: When a class contains a no-arg constructor (default constructor).
import java.io.*; class Student implements Externalizable { String name; int id; String address; // default constructor public Student() { System.out.println("The Default constructor is called!"); } public Student(String name, int id, String address) { this.name= name; this.id = id; this.address = address; } public void writeExternal(ObjectOutput out) throws IOException { // variables saved into the file. out.writeObject(name); out.writeInt(id); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { // Read the variables from a file name = (String)in.readObject(); id = in.readInt(); } } public class ExternalizationDemo { public static void main(String args []) throws Exception { Student obj1 = new Student("Amit", 101, "India"); // Serialize the Student FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); // Method for Serialize our object oos.writeObject(obj1); fos.close(); oos.close(); // deserialize the Student FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); // Method for deserializing our object Student obj2 = (Student) ois.readObject(); fis.close(); ois.close(); System.out.println("The student name is:" +obj2.name); System.out.println("The student Id is:" +obj2.id); System.out.println("The student address is:" +obj2.address); } }
Output:
The default constructor is called! The student name is: Amit The student Id is: 101 The student address is: null
Serialization vs Externalization in Java
1. Serialization is meant for default serialization while Externalization is meant for customized serialization.
2. In serialization, everything takes care of by JVM and the programmer role is very less while in Externalization everything takes care of by the programmer so the programmer role is very important.
3. In serialization, we can always save the total object into a file and it is not possible to save part of the object while in Externalization we can save either the total object or part of the object.
4. In the case of serialization, performance is low while in the case of Externalization performance is high.
5. For object serialization, we just need to implement the Serializable interface and it doesn’t contain any method so it is a marker interface while for object externalization, we just need to implement the Externalizable interface and it contains two methods so it is not a marker interface.
6. Serialization is the best choice if we want to save the total object into a file while Externalization is the best choice if we want to save either total or part of the object into a file.
7. Serializable implemented class not required to contain the no-arg constructor while Externalizable implemented class should compulsorily contain the no-arg constructor otherwise we will get a runtime exception.
8. In serialization, transient keywords play a major role while in externalization transient keywords won’t play any role.
What is SerialVersionUID in Java?
Before talking about SerialVersionUID, let’s discuss a little bit about Serialization and Deserialization after this we will discuss the role of SerialVersionUID.
In Serialization and Deserialization, both the sender and receiver need not be the same and not be from the same location and not to use the same machine ie. person may be different, the location may be different, machine or system may be different than SerialVersionUID comes in picture.
For example: Suppose a person who is in Delhi and another person who is in Mumbai both are trying to perform Serialization and Deserialization respectively.
In this case, to authenticate that the receiver who is in Mumbai is the authenticated person or not, JVM creates a unique id this id is known as SerialVersionUID.
At the time of Deserialization, the receiver side JVM will compare the object’s unique id with the local .class unique id. If both are matched then only deserialization will be performed otherwise receiver unable to deserialize and we will get a runtime exception InvalidClassException.
The sender side JVM is responsible to generate this unique id as the default SerialVersionUID. There are several problems are there if we are depending on the default SerialVersionUID generated by JVM.
1. Both the sender and receiver should use the same JVM, if there is any mismatch in the JVM version then the receiver is unable to deserialize because of different SerialVersionUID, and in this case, we will get a runtime exception InvalidClassException.
2. Both the sender and receiver should use the same .class file version. After Serialization if we changed the .class file at the receiver side then we cannot perform deserialization because of mismatch in SerialVersionUID’s of the local class of receiver and serialized the object and we will get a runtime exception.
3. The sender-side JVM is responsible to generate default SerialVersionUID’s. To generate default SerialVersionUID’s JVM will use internally some complex algorithm that may create a performance problem.
Example of SerialVersionUID
We can solve the above problems by configuring our own SerialVersionUID.
import java.io.*; class Example implements Serializable { // Our own SerialVersionUID private static final long serialVersionUID = 103; int a = 10; int b = 20; } // sender side program to serialize object import java.io.*; class Sender { Example obj1 = new Example(); FileOutputStream fos = new FileOutputStream("abc.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(); } // Receiver side program to deserialize object import java.io.*; class Reciever { public static void main(String args[]){ Example obj1 = new Example(); FileInputStream fis = new FileInputStream("abc.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Example obj2 = (Example)ois.readObject(); System.out.println("The value of a is: ", +obj2.a); System.out.println("The value of b is: ", +obj2.b); } }
Output:
The value of a is: 10 The value of b is 20