1. Core Concepts & Architecture
Definition
Serialization is the process of saving an object’s state only, not its behavior (methods are not serialized). It converts an object into a sequence of bytes to be stored in a file/database or transmitted over a network.
Serialization Engine
- Handled by the
java.io.ObjectOutputStreamclass, which acts as a filter stream wrapped around a lower-level byte stream. - Triggered by invoking
ObjectOutputStream.writeObject(saveThisObject).
Deserialization Engine
- Handled by
java.io.ObjectInputStream. - Triggered by invoking
ObjectInputStream.readObject(), which reads bytes from persistence, reconstructs the object, and returns a genericObjectrequiring explicit type casting (prone toClassCastException).
sequenceDiagram autonumber participant App as Application participant OOS as ObjectOutputStream participant JVM as Serialization Runtime participant Target as Target Object App->>OOS: writeObject(obj) OOS->>JVM: Verify Serializable & check for custom writeObject() alt Custom writeObject defined JVM->>Target: Execute private writeObject(out) else Default Mechanism JVM->>Target: Serialize fields (skip transient/static) end JVM-->>App: Byte Stream Output
2. Compatibility & Eligibility
Class Eligibility
Serializable: Most standard Java classes (Strings, arrays, collections, AWT/Swing GUI components) implement
Serializable.Non-Serializable: System-level resources like
Thread,OutputStream(and subclasses), andSocketare not serializable.
-
Inheritance Rule: If a child class implements
Serializablebut its parent class does not, the parent must have a public or protected no-arg default constructor.-
Non-inherited fields follow standard serialization rules.
-
Inherited fields from non-serializable parents are initialized using the parent’s default constructor during deserialization.
-
3. Important Methods & Interfaces
Key Methods Involved
writeObject()andreadObject()
writeExternal()andreadExternal()
Serializable vs. Externalizable
| Feature | java.io.Serializable | java.io.Externalizable |
|---|---|---|
| Control | Automatic (default mechanism). | Full programmatic control via developer. |
| Methods | Marker interface (no methods). | Must implement writeExternal(ObjectOutput) and readExternal(ObjectInput). |
| Performance | Slower due to reflection overhead. | Faster because fields are written/read manually. |
4. Variables & Modifiers
Static and Transient Behavior
Static variables belong to the class, not the instance, and are not serialized (except for
serialVersionUID).Transient variables are explicitly skipped by the serialization mechanism. During deserialization, they re-initialize to default primitive values (
0,false) ornullfor objects.
5. Exceptions & Versioning
Common Exceptions
NotSerializableException
Thrown when a serializable class holds a reference to a non-serializable field (e.g., an Employee class containing an un-serializable Address field).
InvalidClassException
Thrown when local class definitions are incompatible with the serialized stream, usually due to a serialVersionUID mismatch.
The Role of serialVersionUID
-
A 64-bit hash representing class structure[cite: 1].
-
If you modify a class (e.g., add a new field) without a fixed
serialVersionUID, the JVM generates a new runtime hash[cite: 1]. If you try to deserialize an older byte stream, the hashes will mismatch and throw anInvalidClassException[cite: 1].
Best Practice
Always declare an explicit
serialVersionUID
private static final long serialVersionUID = 1L;
6. Advanced Customization Techniques
A. Customizing Default Protocol (writeObject / readObject)
You can hook into the default process by defining private methods[cite: 1]. The JVM checks for these methods via reflection during serialization[cite: 1].
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject(); // Performs standard serialization first[cite: 1]
// Add custom logic here (e.g., encryption, extra headers)[cite: 1]
}private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject(); // Performs standard deserialization first[cite: 1]
// Add custom logic here (e.g., re-initialize transient states, start threads)[cite: 1]
}B. Blocking Serialization in a Subclass
If your superclass is serializable but you want to prevent a subclass from being serialized, override the private methods to throw a NotSerializableException[cite: 1]:
private void writeObject(ObjectOutputStream out) throws IOException {
throw new NotSerializableException("Serialization is disabled for this secure subclass.");
}private void readObject(ObjectInputStream in) throws IOException {
throw new NotSerializableException("Deserialization is disabled for this secure subclass.");
}7. Modern Security Update (Added Context)
Security Vulnerability Notice
Native Java serialization is a frequent vector for Remote Code Execution (RCE) when reading untrusted streams via
ObjectInputStream.readObject().
- Mitigation (Java 9+): Use
ObjectInputFilterto validate incoming classes before they are deserialized, or avoid native serialization altogether in modern microservices in favor of safe text/binary protocols like JSON (Jackson/Gson) or Protocol Buffers.