In core java interview questions, Serialization is one of the important topic in which we come across various questions like
What is Transient, Explain Serailization, What is serialversionUID, What is use of serialVersionUID, what is Serilization. (interface, class).
I have gone through various technical interview question websites and found that all answers are very short and dosent give idea of interrelated questions.
This tutorial will help beginners to understand everything related to serialization in one go.
Will first start with basic key points.
All objects in memory are exist only as long as java virtual machine running.
Serialization is process of writing objects to a stream and read from stream. Writing to a stream will make your object persistable. We can save object state on physical file system. and read it later whenever required and restore object state.
Using serialization we can maintain object state beyond java virtual machine lifetime.
Java provides mechnisam to persist the object.
Key points to use this mechanisam is. Your object should be serializable.
How can we make our object serializable? by implementing
java.io.Serializble.
What about java library, system classes. Are all of them are serializable? No.
Most of the classes which makes sense to serialize are by default implementing Serializable. But some classes dosent make sense are not.
for E.g : String, Swing, AWT, Class implements Serializable.
Thread, ClassLoader, Socket, OutputStream ..dosent implement Serializable.
Key point to remember is why we need to implement Serializable explicitely? Because java.lang.Object dosent implement serializable. This facility is given to implementer.
What happens if your class is using one of the system class which is not serilizable..for e.g Thread, OutputStream?
Java provides
transient keyword. (As mentioned earlier ..Making Thread serializable dosent make sense) so we can mark this member as transient and Serialization process will exclude this member from serialization.
What will be the value of transient variable when we read it back? it will be default value.. for string null.
Now we understood the concept of serialization, and what is use of transient.
Lets do simple example.
Create simple class.
package transientTest;
import java.io.Serializable;
public class TestClass implements Serializable{
private String fName;
public String getfName() {
return fName;
}
public void setfName(String fName) {
this.fName = fName;
}
public String getlName() {
return lName;
}
public void setlName(String lName) {
this.lName = lName;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
private String lName;
private transient String password;
}
Test the class. Write to file and read from file.
package transientTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestSerialization {
public static void main(String... st) throws Exception{
ObjectOutputStream obj = new ObjectOutputStream(new FileOutputStream(new File("Test.out")));
TestClass ts= new TestClass();
ts.setfName("Shashi");
ts.setlName("Jadhav");
ts.setPassword("pass");
obj.writeObject(ts);
obj.close();
ObjectInputStream objin= new ObjectInputStream(new FileInputStream(new File("Test.out")));
TestClass ts1=(TestClass)objin.readObject();
objin.close();
System.out.println("ts.getfName():"+ts1.getfName());
System.out.println("ts.getlName():"+ ts1.getlName());
// returns null: because TestClass.password is transient.
System.out.println("ts.getPassword():"+ ts1.getPassword());
TestClass1 ts12= (TestClass1)ts1.getTestcls();
System.out.println("test12:"+ts12.mname);
}
}
Looks very simple .. yes!
But we need to look at the few real time scenario.
Suppose you create the object, set the state and write to stream. In same execution you change the state of the object and try to write it again. What will be the behavior... ?
TestClass ts= new TestClass();
ts.setfName("Shashi");
ts.setlName("Jadhav");
ts.setPassword("pass");
obj.writeObject(ts);
ts.setlName("-----");
obj.writeObject(ts);
obj.close();
In above code, you have changed the lName to ---- and again wrote the same object to stream..
Key point to remember.. ObjectOutputStream maintain a reference to an object written to it. That means if the state of the object is written and then written again. the new state will not be saved.
There are two ways to do it.
use reset().
close the stream and write it once again.
obj.reset();
obj = new ObjectOutputStream(new FileOutputStream(new File("Test.out")));
obj.writeObject(ts);
obj.close();
There are few other points you need to consider is about GC. once object is written to stream. make sure that object is availble for GC.
One more key point to remember ...or consider scenario..
You have a class which is persisted, and when you try to read it ... by that time class is modified (added new member..). What will happen?
By default if your class is changed after write.. you will not be able to read it.. because your class is modified. serialization will throw exception java.io.invalidClassException().
How serialization identifies that class is modified.. ?
Best answer is ..all persistent capable classes (Implements Serializable) are automatically given a unique identifier. if the identifier of the class is \not equal to the identifier of saved object.
How to resolve this issue... ? answer is
serialVersionUID.
You assign the serialVersionUID to the class which will remain same before and after modification.
Eg: Create a class using serialVersionUID.
package transientTest.readwritemodify;
import java.io.Serializable;
public class TestClass implements Serializable{
static final long serialVersionUID= 1l;
private String name;
private String lname;
public String getLname() {
return lname;
}
public void setLname(String lname) {
this.lname = lname;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Now.. even if your class is modified but the serialversionUID remains the same.. you will be able to read and write. only additioanl state you have added after modification will be set to null
How can you get serialVersionUID runtime?
use :
ObjectStreamClass.getSerialVersionUID(o.getClass());
serialver is one more utility can be used to get the class version.
What if a super class/interface implements a serializable and you dont want your implementing/extending class to provide this facility.
you can override 2 methods and throw exception.
private void writeObject(ObjectOutputStream out)throws IOException{
throw new NotSerializableException("");
}
private void readObject(ObjectInputStream in) throws IOException{
throw new NotSerializableException("");
}