Converted into the previous clean HTML study-notes format. Original PDF Pages are intentionally not included.
1. Serialization — Introduction
Serialization is the process of converting an object into a byte stream so that the object state can be stored or transmitted.
- Save an object to a file or database.
- Transfer an object over a network.
- Cache or persist object state.
Deserialization is the reverse process: converting the byte stream back into an object.
How to enable serialization
- The class must implement
java.io.Serializable, which is a marker interface. - A
serialVersionUIDcan optionally be declared for version compatibility.
import java.io.Serializable;
class Student implements Serializable {
private static final long serialVersionUID = 1L;
int id;
String name;
}
transient keyword is commonly used for sensitive or irrelevant instance fields such as passwords.2. Serialization and Deserialization Order
Multiple objects can be serialized to the same stream. When reading them back, they must be deserialized in the same logical order in which they were written.
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("abc.ser"));
oos.writeObject(dog);
oos.writeObject(cat);
oos.writeObject(rat);
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("abc.ser"));
Dog d = (Dog) ois.readObject();
Cat c = (Cat) ois.readObject();
Rat r = (Rat) ois.readObject();
3. Basic Serialization Example
A class that implements Serializable can be written using ObjectOutputStream and restored using ObjectInputStream.
class Cat implements Serializable {
int i = 11;
}
class Dog implements Serializable {
int j = 12;
}
class Rat implements Serializable {
int k = 13;
}
// Serialization
FileOutputStream fos = new FileOutputStream("abc.ser");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(new Dog());
oos.writeObject(new Cat());
oos.writeObject(new Rat());
// Deserialization
FileInputStream fis = new FileInputStream("abc.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
Dog d2 = (Dog) ois.readObject();
Cat c2 = (Cat) ois.readObject();
Rat r2 = (Rat) ois.readObject();
System.out.println(d2.j);
System.out.println(c2.i);
System.out.println(r2.k);
The example produces values corresponding to the fields of the restored Dog, Cat and Rat objects.
4. Object Graph in Serialization
An Object Graph is the set of all objects reachable from the object being serialized. During default serialization, reachable serializable objects are automatically included in the serialized graph.
- If a Dog object refers to a Cat object and the Cat refers to a Rat object, serializing Dog can serialize the reachable Cat and Rat objects as well.
- Every object that becomes part of the serialized graph must be serializable.
- If a reachable object is not serializable, serialization can fail with
NotSerializableException.
All reachable objects form the Object Graph
class Dog1 implements Serializable {
Cat1 c1 = new Cat1();
}
class Cat1 implements Serializable {
Rat1 r1 = new Rat1();
}
class Rat1 implements Serializable {
int k = 13;
}
// Serializing Dog1 also serializes its reachable
// Cat1 and Rat1 objects.
5. Transient Keyword
The transient modifier can be applied to an instance field to exclude that field from default serialization.
class Account implements Serializable {
String userName = "sri";
transient String pwd = "sai";
}
Before serialization, the Account object can contain both username and password. After default deserialization, the transient password is not restored and therefore receives its default value, such as null for a String.
| Field | Before serialization | After default deserialization |
|---|---|---|
userName | "sri" | "sri" |
pwd (transient) | "sai" | null |
6. Customized Serialization — writeObject() and readObject()
Default serialization can cause loss of transient information. Customized serialization allows a class to control how its state is written and restored.
Two special private methods are used:
private void writeObject(ObjectOutputStream out)— called automatically during serialization.private void readObject(ObjectInputStream in)— called automatically during deserialization.
These are commonly called callback methods because the JVM invokes them automatically when the serialization process reaches that class.
class Account implements Serializable {
String userName = "sri";
transient String pwd = "sai";
private void writeObject(ObjectOutputStream out)
throws IOException {
out.defaultWriteObject();
out.writeObject(pwd); // custom handling
}
private void readObject(ObjectInputStream in)
throws IOException, ClassNotFoundException {
in.defaultReadObject();
pwd = (String) in.readObject(); // restore
}
}
With customized serialization, the Account object can restore the password even though the field itself is marked transient.
7. Why JVM Can Invoke Private Serialization Methods
Program code normally cannot directly call a private method from outside its class. Serialization is special because the JVM/serialization mechanism uses reflection-like runtime access to invoke the appropriately named private callback methods.
The programmer does not normally call writeObject() or readObject() directly. They are triggered by ObjectOutputStream and ObjectInputStream.
8. Serialization with Inheritance — Case 1
If a parent class implements Serializable, its serializable nature is inherited by child classes. Therefore a child object can be serialized even if the child class does not explicitly declare implements Serializable.
class Animal implements Serializable {
int i = 10;
}
class Dog extends Animal {
int j = 20;
}
// Dog is serializable because Animal is serializable.
Dog d1 = new Dog();
d1.i = 888;
d1.j = 999;
↓
Dog extends Animal → Dog object can be serialized
This is the first important inheritance case described in the source material. fileciteturn14file1L48-L51
9. Serialization with Inheritance — Case 2
A child class can also be serializable even when its parent class is not serializable.
class Animal {
int i = 10;
}
class Dog extends Animal implements Serializable {
int j = 20;
}
- The Dog-specific serializable state is restored from the stream.
- The non-serializable parent's instance state is not obtained from the serialized stream in the normal way.
- During deserialization, the first non-serializable superclass's no-argument constructor is invoked to initialize that part of the object.
- Therefore the first non-serializable superclass must have an accessible no-argument constructor.
- If such a constructor is unavailable, deserialization can fail with
InvalidClassException.
Object itself does not implement Serializable.10. Non-Serializable Parent — Constructor Behavior
When a serializable child has a non-serializable parent, the parent portion is initialized during deserialization through the constructor of the first non-serializable superclass.
class Animal {
int i = 10;
public Animal() {
// no-arg constructor
}
}
class Dog extends Animal implements Serializable {
int j = 20;
}
The source example demonstrates that the serialized child state can retain its values while the non-serializable parent's state is initialized through its constructor/default state.
If the non-serializable parent defines only a parameterized constructor and no accessible no-argument constructor, deserialization can result in an InvalidClassException. fileciteturn14file1L48-L51
11. Externalization — Introduction
Externalization is an alternative to standard serialization that gives the programmer full control over the serialization process.
With Serializable, Java performs default field handling. With Externalizable, the programmer explicitly defines what and how to write and read.
Interface
public interface Externalizable
extends Serializable {
void writeExternal(ObjectOutput out)
throws IOException;
void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException;
}
12. Serializable vs Externalizable
| Feature | Serializable | Externalizable |
|---|---|---|
| Control over process | Automatic/default behavior | Manual custom read/write logic |
| Performance | Can be slower for large/complex objects | Can be faster with carefully optimized logic |
| Interface methods | Marker interface; no methods to implement | Requires writeExternal() and readExternal() |
| No-argument constructor | Not generally required for a serializable class | Public no-arg constructor is required for normal externalization |
| Field selection | Default mechanism handles serializable state; customization is possible | Programmer explicitly chooses what to write/read |
To use Externalization
- Implement
Externalizable. - Override
writeExternal()andreadExternal(). - Define manually which fields are written and read.
- Provide a public no-argument constructor.
13. Externalizable Example
import java.io.*;
public class Employee implements Externalizable {
private String name;
private int age;
// Public no-arg constructor is required
public Employee() {
}
public Employee(String name, int age) {
this.name = name;
this.age = age;
}
// Manual serialization
@Override
public void writeExternal(ObjectOutput out)
throws IOException {
out.writeObject(name);
out.writeInt(age);
}
// Manual deserialization
@Override
public void readExternal(ObjectInput in)
throws IOException, ClassNotFoundException {
name = (String) in.readObject();
age = in.readInt();
}
@Override
public String toString() {
return "Employee{name='" + name + "', age=" + age + "}";
}
}
14. Serializable vs Externalizable — Quick Comparison
| Serialization | Externalization |
|---|---|
| Designed for default serialization. | Designed for customized serialization. |
| JVM handles the default field process. | Programmer controls the fields written/read. |
| Normally the whole serializable object state is handled by the default mechanism. | Only the state explicitly written can be restored. |
| Can have lower performance for large objects depending on the state. | Can provide better performance when optimized. |
Serializable has no methods. | Externalizable requires two methods. |
| No public no-arg constructor requirement solely because of Serializable. | Public no-arg constructor is required for Externalizable deserialization. |
transient plays a role in default serialization. | Field selection is explicitly controlled by writeExternal(). |
15. Use Cases of Externalization
- Custom serialization logic.
- Encrypting or transforming data before it is written.
- Compressing selected fields.
- Selectively including or excluding fields.
- Improving performance for large objects or collections when custom logic is more efficient.
16. serialVersionUID
serialVersionUID is a unique version identifier for a serializable class. It is used during deserialization to check compatibility between the class definition used for serialization and the current class definition.
private static final long serialVersionUID = 1L;
How it works
- The object is serialized together with serialization metadata including the class's serialVersionUID.
- During deserialization, the JVM checks the UID against the currently loaded class.
- If the values are compatible/match, deserialization can proceed.
- If they do not match,
InvalidClassExceptioncan be thrown.
Deserialize → compare stored UID with current UID
Match → continue Mismatch → InvalidClassException
17. Static vs Transient
Static fields belong to the class rather than to an individual object instance. Default object serialization focuses on instance state, so static fields are not serialized as part of each object.
Because static fields are already excluded from default object serialization, declaring a static field as transient is redundant.
| Field | Default serialization | Reason |
|---|---|---|
| Instance field | Serialized unless transient | Part of object state. |
| Static field | Not serialized | Belongs to the class, not an individual instance. |
| Transient instance field | Not serialized | Explicitly excluded by transient. |
18. Final vs Transient
An instance field can technically be declared both final and transient. However, this combination requires care because a transient field is not restored from the stream, while a final field normally needs to be initialized.
class Example implements Serializable {
transient final String value = "data";
}
When transient final state must be reconstructed during deserialization, custom serialization logic may be required. The source material highlights the difficulty of restoring a final field that was intentionally excluded from the serialized state.
19. Transient, Static and Final — Example
class X implements Serializable {
transient static String transientStaticVar =
"transientStaticVar";
transient final String transientFinalVar =
"transientFinalVar";
transient static final String transientStaticFinalVar =
"transientStaticFinalVar";
transient String transientVar = "transientVar";
static {
transientStaticVar = "transientStaticVar";
transientStaticFinalVar = "transientStaticFinalVar";
}
{
// instance initialization
}
}
Observed behavior from the source example
| Field | After deserialization in the example |
|---|---|
| transient static variable | Uses the current static value rather than serialized object state. |
| transient final instance variable | Requires careful initialization because it is transient and final. |
| transient static final variable | Not restored as an instance field; static state belongs to the class. |
| transient instance variable | Receives its default value, such as null for String. |
20. Quick Revision
| Topic | Key point |
|---|---|
| Serialization | Converts an object into a byte stream. |
| Deserialization | Reconstructs an object from a byte stream. |
| Serializable | Marker interface used to enable default serialization. |
| Object Graph | Set of reachable objects serialized along with the root object. |
| Transient | Prevents an instance field from default serialization. |
| Static | Not serialized as part of an individual object's default state. |
| writeObject() | Custom callback for serialization. |
| readObject() | Custom callback for deserialization. |
| Externalizable | Provides explicit manual serialization/deserialization control. |
| writeExternal() | Manually writes the selected externalized state. |
| readExternal() | Manually restores the selected externalized state. |
| serialVersionUID | Version identifier used for serializable class compatibility checks. |
| Non-serializable parent | Its state is initialized through its constructor during child deserialization. |
| InvalidClassException | Can occur for incompatible serialVersionUID or missing required no-arg constructor in a non-serializable superclass. |