In Java, Serialization transforms the state of an active object into a byte stream. This byte stream can be written to a disk file, cached in Redis, or transmitted across network sockets (e.g., in RMI, microservices, or distributed clustering). Deserialization performs the inverse operation: reconstituting the live object on the JVM Heap.
java.io.Serializable is a Marker Interface (it contains zero methods and zero fields). It simply signals the JVM that instances of this class are permissible to serialize.
import java.io.Serializable;
public class Employee implements Serializable {
// Explicit serialVersionUID ensures version compatibility
private static final long serialVersionUID = 1L;
private int id;
private String name;
private double salary;
// transient fields are IGNORED during serialization
private transient String passwordHash;
public Employee(int id, String name, double salary, String passwordHash) {
this.id = id;
this.name = name;
this.salary = salary;
this.passwordHash = passwordHash;
}
@Override
public String toString() {
return "Employee{id=" + id + ", name='" + name + "', salary=" + salary +
", passwordHash='" + passwordHash + "'}";
}
}
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.IOException;
public class SerializeDemo {
public static void main(String[] args) {
Employee emp = new Employee(101, "Aarav Sharma", 85000.0, "secret#SaltedPass2026");
try (FileOutputStream fileOut = new FileOutputStream("employee.ser");
ObjectOutputStream out = new ObjectOutputStream(fileOut)) {
out.writeObject(emp);
System.out.println("Employee object serialized successfully to employee.ser");
} catch (IOException e) {
e.printStackTrace();
}
}
}
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.IOException;
public class DeserializeDemo {
public static void main(String[] args) {
try (FileInputStream fileIn = new FileInputStream("employee.ser");
ObjectInputStream in = new ObjectInputStream(fileIn)) {
// Read object and cast back to Employee
Employee emp = (Employee) in.readObject();
System.out.println("Object Deserialized successfully:");
System.out.println(emp);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
Object Deserialized successfully:
Employee{id=101, name='Aarav Sharma', salary=85000.0, passwordHash='null'}
Notice that passwordHash is null because it was marked transient!
If you do not explicitly define a serialVersionUID, the Java compiler automatically generates one based on class member signatures, interfaces, and methods. However, if you later add even a single comment or harmless method, the compiler's auto-generated hash changes, causing existing stored files to fail with:
java.io.InvalidClassException: Employee; local class incompatible:
stream classdesc serialVersionUID = -248293..., local class serialVersionUID = 718392...
Best Practice: Always declare private static final long serialVersionUID = 1L; explicitly in every serializable class.
static fields are never serialized.Serializable, otherwise a NotSerializableException is thrown.Serializable?
Serializable even if its superclass does not. However, the superclass must have a visible no-argument constructor so the JVM can initialize inherited fields during deserialization.Serializable and Externalizable?
Serializable is a marker interface where serialization logic is automated by the JVM. Externalizable extends Serializable and mandates the implementation of two methods: writeExternal() and readExternal(), giving complete programmer control over serialization format.Accelerate your Java mastery by studying these tightly connected core tutorials:
Byte stream foundations for Object streams.
How objects reside in Heap memory.
Understanding special Java field modifiers.
Closing ObjectOutputStream safely.