Serialization and Deserialization in Java Example
The process of writing a state of an object into a byte stream is called Serialization. The serialization useful when we want to save the state of our program to a persistent storage area, such as a file. The reverse process of serialization that is reading the state of an object from the byte stream is called deserialization. Serialization is also needed to implement Remote Method Invocation (RMI). Remote Method Invocation is an API using which an object can call a method existing in some other address space on the host machine or some remote machine.
Java provides Serializable API encapsulated under java.io package for serializing and deserializing objects which include,
java.io.serializable
java.io.Externalizable
ObjectInputStream
- and
ObjectOutputStream
etc.
Serialization and Deserialization
Serialization is the process of converting a state of the object into a byte stream.
Deserialization is a reverse mechanism where the byte stream is used to recreate the actual Java object in memory.
The process of serialization and deserialization does not depend on the platform, that is an object serialized on one platform can be deserialized on another platform.
If we want to make an object serializable, the class (whose object it is) must implement the Serializable interface.
An object which is going to be serialized may have references to the other objects, which have references to still more objects. Serializing this object will serialize all referenced objects recursively.
If the base class implements the Serializable interface, the subclasses need not implement the Serializable interface explicitly.
The following diagram shows the process of serialization and deserialization in Java.
#Serializable interface
The java.io.Serializable is a marker interface. A marker interface does not contain any data member or method. The String class and all the wrapper classes implement the Serializable interface by default.
#ObjectInputStream class
The ObjectInputStream class can be used to read serializable objects (de-serialization). It is used to perform I/O for objects.
#Constructor
#ObjectInputStream(InputStream i)
It creates an ObjectInputStream that reads from a specified InputStream. It throws IOException.
#Methods
#Object readObject()
It is used to read the state of an object from the input stream. The method throws IOException and ClassNotFoundException.
#void close()
It closes the ObjectInputStream. This method throws IOException.
#ObjectInputSream class
The ObjectOutputStream class can be used to write serializable objects (serialization). It is used to perform I/O for objects.
#Constructor
#ObjectOutputStream(Output o)
It creates an ObjectOuputStream that writes into a specified OutputStream. It throws IOException.
#Methods
#void writeObject(Object ob)
It writes the object into the ObjectOutputStream. it throws the IOException.
#void flush()
If the output stream is having any buffered output bytes, it will be immediately writing them to the specified destination and then flushes the output stream. it throws the IOException.
#void close()
It closes the current output stream. It throws IOException.
#Important Points
- Static data members cannot be saved using serialization. Only non-static data members are saved.
- If you don’t want to save a non-static data member using serialization, make it transient by adding a transient keyword.
- While de-serialization, a constructor of the object never gets called.
#SerialVersionUID
The SerialVersionUID is an id number associated with each Serializable class by the Serialization runtime. It is used to verify at the time of de-serialization that the class loaded by the receiver of the serialized object is compatible with the corresponding sender’s class.
The InvalidClassException occurs when the SerialVersionUIDs in the sender and receiver’s loaded class do not match.
Using the default SerialVersionUID generated by the JVM can be problematic as both the sender and receiver must use the same JVM version and should be on the same platform, otherwise, different SerialVersionUID will be generated.
Therefore, it is always better to create our own SerialVersionUID and it can be done by declaring the static final long UID.
private static final long serialVersionUID = 125L ;
This SerialVersionUIDs of java class can be found using a tool named server. This tool comes with the JVM itself.
See the following program which demonstrates the Serialization in Java.
import java.io.*; //creating a class whose object can be serialized class Student implements Serializable { String name; int age; //constructor public Student(String name, int age) { this.name=name; this.age=age; } //method to print the values of data members public void details() { System.out.println("name of student: "+this.name+"\nage of student: "+this.age); } } class Example1 { public static void main(String [] args) { try { Student s1=new Student("Abhinandan",18); s1.details(); //creating FileOutputStream and ObjectOutputStream for storing the state of the object into a file FileOutputStream f=new FileOutputStream("Object.txt"); ObjectOutputStream op=new ObjectOutputStream(f); op.writeObject(s1); //writing the object op.flush(); //flushing the output stream System.out.println("Object state saved"); op.close(); //closing the output stream } catch(Exception e) { System.out.println("Exception occured"); } } }
See the following output.
Program 2: The following program demonstrates deserialization in Java.
import java.io.*; //creating a class whose object going to be deserialized class Student implements Serializable { String name; int age; //constructor public Student(String name, int age) { this.name=name; this.age=age; } //method to print the values of data members public void details() { System.out.println("name of student: "+this.name+"\nage of student: "+this.age); } } class Example2 { public static void main(String [] args) { try { //creating FileInputStream and ObjectInputStream for fetching the state of the object from a file FileInputStream f=new FileInputStream("Object.txt"); ObjectInputStream inp=new ObjectInputStream(f); Object o=inp.readObject(); //reading the object Student std=(Student)o; //typecasting the fetched object into the required class object System.out.println("Object state fetched"); std.details(); inp.close(); //closing the input stream } catch(Exception e) { System.out.println("Exception occured"); } } }
See the following output.
Program 3: The following program demonstrates the effect of transient data members in Java.
//program to show the effect of transient data member import java.io.*; class Sample implements Serializable { //creating datamembers with default value 0 int x1=0; transient int x2=0; Sample(int a, int b) { x1=a; x2=b; } public void getValue() { System.out.println("x1: "+x1+" x2: "+x2); } } class Example3 { public static void main(String [] args) { //writing object state try { Sample s=new Sample(10,20); System.out.println("values before writing: "); s.getValue(); //creating FileOutputStream and ObjectOutputStream for storing the state of the object into a file FileOutputStream f=new FileOutputStream("Value.txt"); ObjectOutputStream op=new ObjectOutputStream(f); op.writeObject(s); //writing the object op.flush(); //flushing the output stream op.close(); //closing the output stream } catch(Exception e) { System.out.println("Exception occured"); } //reading the object try { //creating FileInputStream and ObjectInputStream for fetching the state of the object from a file FileInputStream f2=new FileInputStream("Value.txt"); ObjectInputStream inp=new ObjectInputStream(f2); Object o=inp.readObject(); //reading the object Sample smp=(Sample)o; //typecasting the fetched object into the required class object System.out.println("values after reading: "); smp.getValue(); inp.close(); //closing the input stream } catch(Exception e) { System.out.println("Exception occured"); } } }
See the output.
Finally, Serialization and Deserialization in Java Example are over.