Serialization in Java
Learn how Java objects can be represented as a byte stream, how serialization and deserialization work, and how to use Serializable, transient fields, serialVersionUID, and safer alternatives for application data.
What is Serialization?
Serialization is the process of converting an object's state into a byte stream so that it can be stored or transmitted.
Deserialization is the reverse process: reconstructing an object from a serialized representation.
Object
↓
Serialization
↓
Byte Stream
↓
Storage / Transfer
↓
Deserialization
↓
Object
Serializable Interface
A class can implement
java.io.Serializable to indicate that its
instances can participate in Java's built-in object
serialization mechanism.
import java.io.Serializable;
class Student implements Serializable {
private String name;
private int age;
}
Serializable is a marker interface. It does not
require implementing methods.
ObjectOutputStream
ObjectOutputStream writes serializable objects to
an output stream.
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
Student student =
new Student();
try (
ObjectOutputStream output =
new ObjectOutputStream(
new FileOutputStream(
"student.ser"
)
)
) {
output.writeObject(student);
}
ObjectInputStream
ObjectInputStream can reconstruct objects from a
serialized stream.
import java.io.FileInputStream;
import java.io.ObjectInputStream;
try (
ObjectInputStream input =
new ObjectInputStream(
new FileInputStream(
"student.ser"
)
)
) {
Student student =
(Student) input.readObject();
}
Complete Serialization Example
import java.io.*;
class Student implements Serializable {
private static final long
serialVersionUID = 1L;
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
Writing the Object
Student student =
new Student(
"Amit",
22
);
try (
ObjectOutputStream output =
new ObjectOutputStream(
new FileOutputStream(
"student.ser"
)
)
) {
output.writeObject(student);
}
Reading the Object
try (
ObjectInputStream input =
new ObjectInputStream(
new FileInputStream(
"student.ser"
)
)
) {
Student student =
(Student) input.readObject();
System.out.println(
student.getName()
);
System.out.println(
student.getAge()
);
}
serialVersionUID
serialVersionUID is a version identifier used
during Java serialization compatibility checks.
private static final long
serialVersionUID = 1L;
Explicitly declaring it makes the intended serialization version easier to control.
InvalidClassException
During deserialization, incompatible class version information
can result in InvalidClassException.
try {
ObjectInputStream input =
new ObjectInputStream(
new FileInputStream(
"student.ser"
)
);
Student student =
(Student) input.readObject();
}
catch (InvalidClassException exception) {
System.out.println(
"Incompatible serialized class"
);
}
transient Keyword
A field marked transient is skipped by the
default Java serialization mechanism.
class User implements Serializable {
private String username;
private transient String password;
}
transient as a general security
mechanism. Sensitive data should be handled using appropriate
application-level security practices.
Static Fields and Serialization
Static fields belong to the class rather than to an individual object, so they are not part of an object's serialized instance state.
class Counter implements Serializable {
private static int count;
private int value;
}
The instance field value can participate in
serialization, while the static field
count does not represent per-object serialized
state.
Object Graph Serialization
Serialization can traverse referenced objects as part of an object graph, provided the relevant referenced objects are serializable.
class Address implements Serializable {
private String city;
}
class Employee implements Serializable {
private String name;
private Address address;
}
NotSerializableException.
NotSerializableException
If the serialization mechanism encounters a non-transient
field whose runtime object is not serializable, Java can throw
NotSerializableException.
try {
output.writeObject(employee);
}
catch (NotSerializableException exception) {
System.out.println(
"Object cannot be serialized"
);
}
Custom Serialization Hooks
A serializable class can define private
writeObject() and
readObject() methods to customize the default
serialization process.
private void writeObject(
ObjectOutputStream output
) throws IOException {
output.defaultWriteObject();
}
private void readObject(
ObjectInputStream input
) throws IOException,
ClassNotFoundException {
input.defaultReadObject();
}
Externalizable
Externalizable provides more explicit control
over serialization by requiring implementations of
writeExternal() and
readExternal().
class Student
implements Externalizable {
public Student() {
}
public void writeExternal(
ObjectOutput output
) throws IOException {
// write fields explicitly
}
public void readExternal(
ObjectInput input
) throws IOException,
ClassNotFoundException {
// read fields explicitly
}
}
Externalizable is a specialized mechanism and requires careful handling of the serialization contract.
Serialization and Inheritance
If a serializable subclass extends a non-serializable superclass, the superclass portion is not restored through default serialization. The first accessible no-argument constructor of the non-serializable superclass is involved during deserialization.
class Person {
protected String name;
}
class Student
extends Person
implements Serializable {
private int age;
}
Serialization Security
Java native deserialization can be dangerous when untrusted serialized data is accepted because deserialization can invoke class-specific behavior and reconstruct complex object graphs.
Alternatives to Native Serialization
Modern applications often use explicit data formats such as JSON or other protocol formats instead of Java native serialization for external communication.
| Approach | Typical Use |
|---|---|
| Java Serialization | Legacy/internal object persistence scenarios |
| JSON | REST APIs and human-readable data exchange |
| Protocol Buffers | Efficient structured service communication |
| Database Persistence | Long-term structured application data |
Java Serialization vs JSON
| Feature | Java Serialization | JSON |
|---|---|---|
| Format | Java-specific binary format | Text format |
| Language Interoperability | Limited | Excellent |
| Human Readable | No | Yes |
| External Input | Requires strong security controls | Still requires validation |
Example: Saving Student Data 🤓👨🏫
class Student implements Serializable {
private static final long
serialVersionUID = 1L;
private String name;
private int age;
Student(String name, int age) {
this.name = name;
this.age = age;
}
}
Student student =
new Student(
"Neha",
21
);
try (
ObjectOutputStream output =
new ObjectOutputStream(
new FileOutputStream(
"student.ser"
)
)
) {
output.writeObject(student);
}
System.out.println(
"Student saved"
);
Serialization Best Practices
- Use try-with-resources for serialization streams.
-
Declare
serialVersionUIDexplicitly when using Java serialization. -
Mark fields that should not be serialized as
transientwhen appropriate. - Avoid native Java deserialization of untrusted data.
- Prefer explicit data-transfer formats for external APIs.
- Consider whether long-term persistence should use a database or a stable application-level data format.
Interview Questions
Summary
Java serialization converts object state into a byte stream and deserialization reconstructs objects from that stream. Important concepts include Serializable, ObjectOutputStream, ObjectInputStream, serialVersionUID, transient fields, object graphs, custom serialization, and the security risks of native deserialization.