Serializable Interface and serialVersionUID
The Serializable interface in Java, in java.io, is a marker interface: it has no methods, it simply marks a class as allowed to be serialized. The serialVersionUID is a long number that identifies the version of a serializable class. When an object is read back, Java compares the number stored in the bytes with the number of the current class; if they differ, deserialization fails with InvalidClassException. In this lesson, you will learn both, and see what happens when a class changes after its objects were saved.
Declaration
public interface Serializable { }
class Student implements Serializable {
private static final long serialVersionUID = 1L;
}Why serialVersionUID Matters
If a class doesn't declare serialVersionUID, Java computes one from the class's details: its name, fields, methods and more. Almost any change to the class, even adding a field, produces a different number, so objects saved earlier can no longer be read. Declaring the number yourself keeps it stable, so compatible changes such as adding a field still work.
| Situation | Without a declared serialVersionUID | With serialVersionUID = 1L |
|---|---|---|
| Add a field | InvalidClassException | Works; the new field gets its default value |
| Remove a field | InvalidClassException | Works; the old value is ignored |
| Change a field's type | InvalidClassException | InvalidClassException (incompatible) |
The Checkpoint: Changing a Saved Class
This experiment uses three files. Save.java writes a Student, Load.java reads it back, and between the two runs the Student class is changed. Each program is compiled and run separately, so the output comes from real terminal runs.
import java.io.Serializable;
public class Student implements Serializable {
String name;
int marks;
Student(String name, int marks) {
this.name = name;
this.marks = marks;
}
}import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Save {
public static void main(String[] args) throws IOException {
try (ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("student.ser"))) {
out.writeObject(new Student("Navika", 91));
}
System.out.println("Saved");
}
}import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class Load {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
try (ObjectInputStream in = new ObjectInputStream(
new FileInputStream("student.ser"))) {
Student s = (Student) in.readObject();
System.out.println("Loaded " + s.name + " " + s.marks);
}
}
}First, save and load with the class unchanged:
javac Student.java Save.java Load.java
java Save
java LoadSaved
Loaded Navika 91Now add one field, String city;, to Student, recompile only Student.java, and load the old file again:
Exception in thread "main" java.io.InvalidClassException: Student; local class incompatible: stream classdesc serialVersionUID = -3428531181827717244, local class serialVersionUID = -8902825101767173921
at java.base/java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:496)
...Explanation: The saved bytes carry the number Java computed for the old class. Adding city changed the computed number for the new class, so the two don't match and reading fails. Repeating the experiment with private static final long serialVersionUID = 1L; in Student from the start, the same change loads fine and prints Loaded Navika 91 null: the new city field simply gets its default value, null.
Rules of Serializable
- A class is serializable if it, or any superclass, implements
Serializable. - All fields that will be saved must hold serializable objects (or be
transient). - Fields that are
staticortransientaren't saved. - Most JDK classes, such as
String, wrappers,ArrayList,HashMapandLocalDate, are serializable.
Common Mistakes
Leaving out serialVersionUID. Every small change breaks old saved data.
Changing serialVersionUID for compatible changes. It makes old data unreadable for no reason.
Assuming Serializable has methods to implement. It's a marker with none.
Interview Corner
What is serialVersionUID, and why should you declare it?
serialVersionUID is a private static final long that identifies the version of a serializable class. During deserialization, Java compares the value stored in the stream with the value of the local class and throws InvalidClassException if they differ. If it isn't declared, Java computes it from the class structure, so almost any change, even adding a field, changes it and breaks compatibility with previously saved objects. Declaring it explicitly keeps compatible changes working.
Practice
- Easy: Add
serialVersionUIDto a serializable class of your own and annotate it with@Serial. - Harder: Repeat the checkpoint, but change
marksfrominttoStringwhile keepingserialVersionUID = 1L. What exception do you get, and why?
Key Takeaways
Was this tutorial helpful?