Serializable is a marker interface.
When an object has to be transferred over a network (typically through rmi or EJB) or to persist the state of an object to a file, the 'object' Class needs to implement 'Serializable' interface.
Implementing this interface will allow the object to be converted into bytestream and transfer over a network.
During object serialization, the default Java serialization mechanism writes the metadata about the object, which includes the class name, field names, types and superclass.
This class definition is stored as a part of the serialized object. This stored metadata enables the deserialization process to reconstitute the objects and map the stream data into the class attributes with the appropriate type.
Everytime an object is serialized the java serialization mechanism automatically computes a hash value. ObjectStreamClass's computeSerialVersionUID() method passes the class name, sorted member names, modifiers and interfaces to the secure hash algorithm (SHA), which returns a hash value.
The 'serialVersionUID' is also called 'suid'. So when the serilaize object is retrieved , the JVM first evaluates the suid of the serialized class and compares the suid value with one of the object. If the suid values match then the object is said to be compatible with the class and hence it is de-serialized. If not 'InvalidClassException' is thrown.
Changes to a serializable class can be compatible or incompatible. Following is the list of changes which are compatible:
Add fields
Change a field from static to non-static
Change a field from transient to non-transient
Add classes to the object tree
List of incompatible changes:
Delete fields
Change class hierarchy
Change non-static to static
Change non-transient to transient
Change type of a primitive field
So, if no suid is present, inspite of making compatible changes, jvm generates new suid thus resulting in an exception if prior release version object is used.
The only way to get rid of the exception is to recompile and deploy the application again.
If we explicitly mention the sUid using the statement:
private final static long serialVersionUID
then if any of the mentioned compatible changes are made the class need not be recompiled. But for incompatible changes there is no other way than to compile again.
The serialization is used:
To send state of one or more object's state over the network through a socket.
To save the state of an object in a file.
An object's state needs to be manipulated as a stream of bytes.
Besides the Serializable interface, at least three other alternate approaches can serialize Java objects:
For object serialization, instead of implementing the Serializable interface, a developer can implement the 'Externalizable' interface, which extends Serializable. By implementing Externalizable, a developer is responsible for implementing the 'writeExternal()' and 'readExternal()' methods. As a result, a developer has sole control over reading and writing the serialized objects.
'XML' serialization is an often-used approach for data interchange. This approach lags runtime performance when compared with Java serialization, both in terms of the size of the object and the processing time. With a speedier XML parser, the performance gap with respect to the processing time narrows. Nonetheless, XML serialization provides a more malleable solution when faced with changes in the serializable object.
Finally, consider a 'roll-your-own' serialization approach. You can write an object's content directly via either the 'ObjectOutputStream' or the 'DataOutputStream'. While this approach is more involved in its initial implementation, it offers the greatest flexibility and extensibility. In addition, this approach provides a performance advantage over Java serialization.
No. Serializable is a Marker Interface. It does not have any methods.
If the object to be serialized includes references to the other objects, then all those object's state will also be saved as the part of the serialized state of the object in question. The whole object graph of the object to be serialized will be saved during serialization automatically provided all the objects included in the object's graph are serializable.
If you try to serialize an object of a class which implements serializable, but the object includes a reference to a non-serializable class then a 'NotSerializableException' will be thrown at runtime.
public class NonSerial_JBK
{
//This is a non-serializable class
}
public class MyClass_JBK implements Serializable
{
private static final long serialVersionUID = 1L;
private NonSerial_JBK nonSerial;
MyClass_JBK(NonSerial_JBK nonSerial)
{
this.nonSerial = nonSerial;
}
public static void main(String [] args)
{
NonSerial_JBK nonSer = new NonSerial_JBK();
MyClass_JBK c = new MyClass_JBK(nonSer);
try {
FileOutputStream fs = new FileOutputStream("test1.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(c);
os.close();
}
catch (Exception e)
{
e.printStackTrace();
} try {
FileInputStream fis = new FileInputStream("test1.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
c = (MyClass_JBK) ois.readObject();
ois.close();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
On execution of above code following exception will be thrown:
java.io.NotSerializableException: NonSerial_JBK
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java)
No. The static variables belonging to the class are not the part of the state of an object so they are not saved as the part of serialized object.
These variables are not included in the process of serialization and are not the part of the object's serialized state.
The value of transient variable after de-serialization will be its default value. Say for instance if the transient variable in question is an 'int', its value after deserialization will be zero.
public class TestTransientVal_JBK implements Serializable
{
private static final long serialVersionUID = -22L;
private String name;
transient private int age;
TestTransientVal_JBK(int age, String name)
{
this.age = age;
this.name = name;
}
public static void main(String [] args)
{
TestTransientVal_JBK c = new TestTransientVal_JBK(1,"ONE");
System.out.println("Before serialization:" + c.name + " "+ c.age);
try {
FileOutputStream fs =new FileOutputStream("testTransient.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(c);
os.close();
}
catch (Exception e)
{
e.printStackTrace();
}
try {
FileInputStream fis =new FileInputStream("testTransient.ser");
ObjectInputStream ois =new ObjectInputStream(fis);
c = (TestTransientVal_JBK) ois.readObject();
ois.close();
} catch (Exception e)
{
e.printStackTrace();
}
System.out.println("After de-serialization:" + c.name +" "+ c.age);
}
}
Result of the above piece of code is:
Output:
Before serialization : Value of non-transient variable ONE Value of transient variable 1
After de-serialization : Value of non-transient variable ONE Value of transient variable 0
Explanation for the same is as follows:
The transient variable is not saved as the part of the state of the serialized variable, it's value after de-serialization is it's 'default' value.
Yes, while restoring the object's state the transient variables and the serializable variables that are stored must be restored in the same order in which they were saved.