Java serialization is the process of converting an object into a stream of bytes so we can do stuff like store it on disk or send it over the network. Deserialization is the reverse process – converting a stream of bytes into an object in memory.
During serialization, the java runtime associates a version number with each serializable class. This number is called serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender’s class, then deserialization will result in an InvalidClassException.
1. Java SerialVersionUID Syntax
A Serializable class can declare its own SerialVersionUID explicitly by declaring a field named “serialVersionUID” that must be static, final, and of type long.
private static final long serialVersionUID = 1L;
Here the serialVersionUID represents the class version, and we should increment it if the current version of the class is modified such that it is no longer backward compatible with its previous version.

2. Java Serialization and Deserialization Examples
Let us see an example of how a class is serialized and then deserialized.
import java.io.*;
import java.util.logging.Logger;
public class DemoClass implements java.io.Serializable {
private static final long serialVersionUID = 4L; //Default serial version uid
private static final String fileName = "DemoClassBytes.ser"; //Any random name
private static final Logger logger = Logger.getLogger("");
//Few data fields
//Able to serialize
private static String staticVariable;
private int intVariable;
//Not able to serialize
transient private String transientVariable = "this is a transient instance field";
private Thread threadClass;
public static void main(String[] args) throws IOException, ClassNotFoundException
{
//Serialization
DemoClass test = new DemoClass();
test.intVariable = 1;
staticVariable = "this is a static variable";
writeOut(test);
System.out.println("DemoClass to be saved: " + test);
//De-serialization
System.out.println("DemoClass deserialized: " + readIn());
}
private static Object readIn() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new File(fileName)));
return ois.readObject();
}
private static void writeOut(java.io.Serializable obj) throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(fileName)));
oos.writeObject(obj);
oos.close();
}
@Override public String toString() {
return "DemoClass: final static fileName=" + fileName + ", final static logger=" + logger
+ ", non-final static staticVariable=" + staticVariable + ", instance intVariable=" + intVariable
+ ", transient instance transientVariable=" + transientVariable + ", non-serializable instance field threadClass:=" + threadClass;
}
}
Program Output.
DemoClass to be saved: DemoClass:
final static fileName=DemoClassBytes.ser,
final static logger=java.util.logging.LogManager$RootLogger@1d99a4d,
non-final static staticVariable=this is a static variable,
instance intVariable=1,
transient instance transientVariable=this is a transient instance field,
non-serializable instance field threadClass:=null
//Execute readIn() function from a separate main() method
//to get given below output correctly. It will flush out the static fields.
DemoClass deserialized: DemoClass:
final static fileName=DemoClassBytes.ser,
final static logger=java.util.logging.LogManager$RootLogger@cd2c3c,
non-final static staticVariable=null,
instance intVariable=1,
transient instance transientVariable=null,
non-serializable instance field threadClass:=null
If a serializable class does not explicitly declare a
serialVersionUID, then the serialization runtime will calculate a defaultserialVersionUIDvalue for that class based on various aspects of the class.
3. How to Generate SerialVersionUID
Joshua Bloch says in Effective Java that the automatically generated UID is generated based on a class name, implemented interfaces, and all public and protected members. Changing any of these in any way will change the serialVersionUID.
However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations and can produce different serialVersionUID in different environments. This can result in unexpected InvalidClassException during deserialization.
Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier in serialVersionUID where possible, since such declarations apply only to the immediately declaring class.
Also, note that serialVersionUID field is not helpful as an inherited member.
Based on my short career, I can say that storing serialized data for a long time span [spatial serialization] is not a very common usecase. It is far more common to use the serialization mechanism to temporarily write data [temporal serialization] to for instance a cache or send it over the network to another program to utilize the information.
In such cases, we are not interested in maintaining backward compatibility. We are only concerned with making sure that the code bases which are communicating on the network, indeed have the same version of relevant classes. In order to facilitate such a check, we must maintain the serialVersionUID just as it is and don’t change it. Also, do not forget to update it when making incompatible changes to your classes, on both sides of applications on the network.
4. Java Classes without SerialVersionUID
It is not the situation that we ever want to face. But, it’s reality and sometimes it happens (should i say rarely?). If we need to change such a class in an incompatible way but want to maintain serialization/deserialization capability with the old version of the class, we can use the JDK tool “serialver“. This tool generates the serialVersionUID on the old class, and explicitly set that on the new class. Do not forget to to implement readObject() and writeObject() methods because the built-in deserialization mechanism (in.defaultReadObject()) will refuse to deserialize from old versions of the data.
If we define our own readObject() function which can read back old data. This custom code should check the serialVersionUID in order to know which version the data is in and decide how to deserialize it. This versioning technique is helpful if we store serialized data that survives several versions of your code.
Read more : Java serialization compatible and incompatible changes
5. Summary
- The
transientandstaticfields are ignored in serialization. After deserializationtransientfields and non-final static fields will be null.finalandstaticfields still have values since they are part of the class data. ObjectOutputStream.writeObject(obj)andObjectInputStream.readObject()are used in serialization and deserialization.- During serialization, we need to handle
IOException; during deserialization, we need to handleIOExceptionandClassNotFoundException. So the deserialized class type must be in the classpath. - Uninitialized non-serializable, non-transient instance fields are tolerated.
When adding “
private Thread th;“, no error in serializable. However, “private Thread threadClass = new Thread();” will cause exception:
Exception in thread "main" java.io.NotSerializableException: java.lang.Thread
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at com.howtodoinjava.demo.serialization.DemoClass.writeOut(DemoClass.java:42)
at com.howtodoinjava.demo.serialization.DemoClass.main(DemoClass.java:27)
- Serialization and deserialization can be used for copying and cloning objects. It is slower than a regular clone but can produce a deep copy very quickly.
- If I need to serialize a
SerializableclassEmployee, but one of its superclasses is not Serializable, canEmployeeclass still be serialized and deserialized? The answer is yes, provided that the non-serializable super-class has a no-arg constructor, which is invoked at deserialization to initialize that super-class. - We must be careful while modifying a class and implementing
java.io.Serializable. If the class does not contain aserialVersionUIDfield, its serialVersionUID will be automatically generated by the compiler.Different compilers, or different versions of the same compiler, will generate potentially different values.
Computation of
serialVersionUIDis based not only on fields but also on other aspects of the class like implement clauses, constructors, etc. So the best practice is explicitly declaring aserialVersionUIDfield to maintain backward compatibility. If we need to modify the serializable class substantially and expect it to be incompatible with previous versions, then we need to increment serialVersionUID to avoid mixing different versions.
Happy Learning !!
Hi Lokesh,
When i ran the problem i am getting below output.
DemoClass to be saved: DemoClass: final static fileName=DemoClassBytes.ser, final static logger=java.util.logging.LogManager$RootLogger@7d4991ad, non-final static staticVariable=this is a static variable, instance intVariable=1, transient instance transientVariable=this is a transient instance field, non-serializable instance field threadClass:=null
DemoClass deserialized: DemoClass: final static fileName=DemoClassBytes.ser, final static logger=java.util.logging.LogManager$RootLogger@7d4991ad, non-final static staticVariable=this is a static variable, instance intVariable=1, transient instance transientVariable=null, non-serializable instance field threadClass:=null
After running this problem I am getting non-final static fields will not be null.
Can you please elaborate.
Yes. static variables are the part of class so on deserialization, Static variable value will be loaded with current value defined in the class.
The result mentioned in the example is wrong and need to be corrected.
static field do not serialize then why we make SerialVersionUDI static?
I assume because the serialVersionUID is not serialized but the class is. Also its not required to serialize the serialVersionUID. Its just for the JVM to uniquely identify the class during deserialization.
Hi Lokesh,
What is the difference whether we use default serial version UID i.e private static final long serialVersionUID = 1L; or generated serial version UID (using IDE e.g eclipse or IntelliJ)
-Manoj
Serial version id is used while de-serialization. If they don’t match, de-serialization fails. If its generated, then changing class structure will change the serial version id as well. You can assume them as version number for classes.
My question was that if i decide to have the serialVersionUID field in the class not let the JVM generate it.
There are two ways.
1) private static final long serialVersionUID = 1L;
Give 1,2 ,3 etc numbers
2) Generate it through eclipse one time.
So what is the difference between these two aproaches? de-serialization will still pass in both the cases but is there any problem we have it 1L always?
Suppose other classes and for all classes I give 1L , will it make any difference?
if you have already serialized and saved with an older version of code, you will want to have it matching the serialized
Really good explanation !!
Hi Lokesh,
You stated that static fields can not be serialized. But i can get the static field data after deserialization.
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
String Name;
static int age = 11;
Employee(String n) {
this.Name = n;
}
}
public class SerializableTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Employee e1 = new Employee(“Sunil”);
FileOutputStream fp = new FileOutputStream(“employee.ser”);
ObjectOutputStream op = new ObjectOutputStream(fp);
op.writeObject(e1);
System.out.println(“—————serialization done”);
FileInputStream fs = new FileInputStream(“employee.ser”);
ObjectInputStream os = new ObjectInputStream(fs);
Employee e2 = (Employee)os.readObject();
System.out.println(“———————-deserialization done \n”);
System.out.println(“data after deserialization is”+ e2.Name + “—-“+ e2.age);
}
}
Let me know if i am missing anything.
Thanks,
Sunil.
Hi Sunil,
You are assigning the value of age during instance creation (initialized with it). So, when de-serilization happens; it first creates a blank object (age is set at this stage only); and now serialized values are read and overwritten on field of Employee instance.
To further clear the concept, I have modified your program and divided the serialization/de-serialization process into two methods. Please run the code into two steps. In first step, comment out the method call “deserializeEmployee()” inside main method. And in second step, comment out the method “serializeEmployee()”, so that fresh object is built using serialized data.
I have removed the static initialization from Employee class, and writing to it when I am serializing the Employee class only. If it was serialized then I must get it back during deserialization, BUT i do not.
public class SerializableTest { public static void main(String[] args) throws IOException, ClassNotFoundException { //serializeEmployee(); deserializeEmployee(); } @SuppressWarnings("resource") private static void serializeEmployee() throws IOException, ClassNotFoundException { Employee e1 = new Employee("Sunil"); //Modified the static value before writing it to employee.ser e1.age = 31; FileOutputStream fp = new FileOutputStream("employee.ser"); ObjectOutputStream op = new ObjectOutputStream(fp); op.writeObject(e1); System.out.println("—————serialization done"); System.out.println("data after serialization is + —-" + e1.age); } @SuppressWarnings("resource") private static void deserializeEmployee() throws IOException, ClassNotFoundException { FileInputStream fs = new FileInputStream("employee.ser"); ObjectInputStream os = new ObjectInputStream(fs); Employee e2 = (Employee) os.readObject(); System.out.println("———————-deserialization done n"); System.out.println("data after deserialization is + —-" + e2.age); } } class Employee implements Serializable { private static final long serialVersionUID = 1L; String Name; static int age = 0; Employee(String n) { this.Name = n; } }Hi Lokesh,
“If I need to serialize a Serializable class Employee, but one of its super classes is not Serializable, can Employee class still be serialized and de-serialized? The answer is yes, provided that the non-serializable super-class has a no-arg constructor, which is invoked at de-serialization to initialize that super-class.”
In one of my business use case i need to implement the reverse of the above quoted line i.e. serializing the super class “Employee” using the subclass object “Manager”, but unfortunately i didn’t find any way for doing it, as by default the subclass object also get serialized.
So is there any way of serializing only the super class using your subclass ref without change the structure of the subclass.?
Mark all fields in Manager class “transient”. It will prevent the subclass fields to serialize and still you have the same structure.
Hi Lokesh,
thx for the replay, Can you please explain how the Externalization is different from Serialization, i mean from the doc readExternal() and writeExternal() allows more control over the field then the readObject() and writeObject() but the same flexibility can be achieve once you customized the Serialization and implement your logic inside read/writeObject(). so where is the key difference then ?
Basically, the difference between Serializable and Externalizable is on default capabilities. Classes which implement Serializable, the serialization of the object is taken care of automatically, while classes that implement Externalizable is responsible for serializing itself, without the help of default serialization procedures.
Only the identity of the class of an Externalizable instance is written in the serialization stream and it is the responsibility of the class to save and restore the contents of its instances. The writeExternal and readExternal methods of the Externalizable interface are implemented by a class to give the class complete control over the format and contents of the stream for an object and its supertypes.
Hi Lokesh,
i too have the similar thought on this, hope along with the javadoc in near future Oracle may release the doc with reason behind the design :)
detail information about serialization.
Very detailed explanation specially the Fast Facts.. Thanks for sharing and increasing the readers’ knowledge here..
really good. it contains all the thing in serilization. I want to know serlizable iterface is marker interface. so ,how jvm works with this marker interface, as of in marker interface no, method.
Using instanceof operator.
can you show me the code or api.
Regarding which concept?
U said, non-static fields are not serialized but in the output of the program, I can see “non-final static staticVariable=this is a static variable”? Am I missing something?
Pretty good observation. The reason that static value was (looked like deserialized) printed because I executed the program in one go (read and write). So the static value was all the time in memory. Though It was not read in de-serialization, though it was pre-set in class, so got printed.
Anyway, I put a comment in program so that next person do not confuse.
Thanks for pointing it out.
good info lokesh, its really helpful for all Java Lovers
Very good information keep it up !!!