Java Notes
Complete guide to Serialization in Java — converting objects to byte streams, Serializable interface, ObjectOutputStream, transient keyword, serialVersionUID, and custom serialization.
What is Serialization?
Serialization is the process of converting a Java object's state into a byte stream, so it can be:
- Saved to a file (persistence)
- Sent over a network (remote communication)
- Stored in a database (as BLOB)
- Cached in memory systems (Redis, Memcached)
Serialization
Java Object →→→ Byte Stream →→→ File/Network/Database
(in memory) (portable) (persistent storage)
Deserialization (reverse)
File/Network →→→ Byte Stream →→→ Java Object
(storage) (portable) (back in memory)
The Serializable Interface
To make a class serializable, implement java.io.Serializable:
import java.io.Serializable;
// Serializable is a MARKER interface (no methods to implement)
public class Student implements Serializable {
private String name;
private int age;
private double gpa;
public Student(String name, int age, double gpa) {
this.name = name;
this.age = age;
this.gpa = gpa;
}
@Override
public String toString() {
return String.format("Student{name='%s', age=%d, gpa=%.2f}", name, age, gpa);
}
}Basic Serialization with ObjectOutputStream
import java.io.*;
class Employee implements Serializable {
private String name;
private int id;
private double salary;
private String department;
public Employee(String name, int id, double salary, String department) {
this.name = name;
this.id = id;
this.salary = salary;
this.department = department;
}
@Override
public String toString() {
return String.format("Employee{id=%d, name='%s', salary=%.2f, dept='%s'}",
id, name, salary, department);
}
}
public class SerializationBasic {
public static void main(String[] args) {
Employee emp = new Employee("Alice Johnson", 1001, 75000.50, "Engineering");
System.out.println("=== Serialization Demo ===\n");
System.out.println("Object to serialize: " + emp);
// Serialize (write object to file)
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("employee.ser"))) {
oos.writeObject(emp);
System.out.println("\n✓ Object serialized to 'employee.ser'");
System.out.println(" File size: " + new File("employee.ser").length() + " bytes");
} catch (IOException e) {
System.out.println("Serialization error: " + e.getMessage());
}
// Deserialize (read object from file)
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("employee.ser"))) {
Employee restored = (Employee) ois.readObject();
System.out.println("\n✓ Object deserialized from file:");
System.out.println(" " + restored);
} catch (IOException | ClassNotFoundException e) {
System.out.println("Deserialization error: " + e.getMessage());
}
new File("employee.ser").delete();
}
}Output:
The transient Keyword
Fields marked transient are excluded from serialization:
import java.io.*;
class UserAccount implements Serializable {
private String username;
private transient String password; // NOT serialized!
private transient int loginAttempts; // NOT serialized!
private String email;
private String role;
public UserAccount(String username, String password, String email, String role) {
this.username = username;
this.password = password;
this.email = email;
this.role = role;
this.loginAttempts = 0;
}
@Override
public String toString() {
return String.format(
"UserAccount{user='%s', pass='%s', email='%s', role='%s', attempts=%d}",
username, password, email, role, loginAttempts);
}
}
public class TransientExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
UserAccount account = new UserAccount("alice", "secret123", "alice@mail.com", "admin");
System.out.println("=== Transient Keyword Demo ===\n");
System.out.println("Before serialization: " + account);
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("user.ser"))) {
oos.writeObject(account);
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("user.ser"))) {
UserAccount restored = (UserAccount) ois.readObject();
System.out.println("After deserialization: " + restored);
}
System.out.println("\nNotice: password is null, loginAttempts is 0");
System.out.println("Transient fields get their DEFAULT values:");
System.out.println(" - Objects → null");
System.out.println(" - int → 0");
System.out.println(" - boolean → false");
System.out.println(" - double → 0.0");
new File("user.ser").delete();
}
}Output:
| Before serialization | UserAccount{user='alice', pass='secret123', email='alice@mail.com', role='admin', attempts=0} |
| After deserialization | UserAccount{user='alice', pass='null', email='alice@mail.com', role='admin', attempts=0} |
| Notice | password is null, loginAttempts is 0 |
| - Objects | null |
| - int | 0 |
| - boolean | false |
| - double | 0.0 |
serialVersionUID
The serialVersionUID is a version identifier for the serialized class. It ensures compatibility between the serializer and deserializer:
import java.io.*;
class Product implements Serializable {
// Explicitly declare serialVersionUID
private static final long serialVersionUID = 1L;
private String name;
private double price;
private int quantity;
public Product(String name, double price, int quantity) {
this.name = name;
this.price = price;
this.quantity = quantity;
}
@Override
public String toString() {
return String.format("Product{name='%s', price=%.2f, qty=%d}", name, price, quantity);
}
}
public class SerialVersionUIDExample {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("=== serialVersionUID Demo ===\n");
Product product = new Product("Laptop", 999.99, 50);
// Serialize
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("product.ser"))) {
oos.writeObject(product);
System.out.println("Serialized: " + product);
}
// Deserialize
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("product.ser"))) {
Product restored = (Product) ois.readObject();
System.out.println("Deserialized: " + restored);
}
System.out.println("\n--- What serialVersionUID Prevents ---");
System.out.println("Without explicit serialVersionUID:");
System.out.println(" 1. Serialize object (class version A)");
System.out.println(" 2. Modify class (add/remove field) → version B");
System.out.println(" 3. Deserialize → InvalidClassException!");
System.out.println("");
System.out.println("With explicit serialVersionUID = 1L:");
System.out.println(" 1. Serialize object (serialVersionUID = 1L)");
System.out.println(" 2. Add new field (keep serialVersionUID = 1L)");
System.out.println(" 3. Deserialize → WORKS! New field gets default value");
new File("product.ser").delete();
}
}Serializing Multiple Objects
import java.io.*;
import java.util.*;
class Contact implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private String phone;
private String email;
public Contact(String name, String phone, String email) {
this.name = name;
this.phone = phone;
this.email = email;
}
@Override
public String toString() {
return String.format("%-15s | %-12s | %s", name, phone, email);
}
}
public class MultipleObjects {
public static void main(String[] args) throws IOException, ClassNotFoundException {
System.out.println("=== Serializing Multiple Objects ===\n");
// Create contacts
List<Contact> contacts = new ArrayList<>(Arrays.asList(
new Contact("Alice", "555-0101", "alice@mail.com"),
new Contact("Bob", "555-0102", "bob@mail.com"),
new Contact("Charlie", "555-0103", "charlie@mail.com"),
new Contact("Diana", "555-0104", "diana@mail.com")
));
// Method 1: Serialize entire collection
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("contacts.ser"))) {
oos.writeObject(contacts);
System.out.println("✓ Serialized " + contacts.size() + " contacts as List");
}
// Method 2: Deserialize entire collection
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("contacts.ser"))) {
@SuppressWarnings("unchecked")
List<Contact> restored = (List<Contact>) ois.readObject();
System.out.println("\nRestored contacts:");
System.out.printf("%-15s | %-12s | %s%n", "Name", "Phone", "Email");
System.out.println("-".repeat(50));
restored.forEach(System.out::println);
}
new File("contacts.ser").delete();
}
}Output:
Serialization with Inheritance
Output:
Custom Serialization (writeObject / readObject)
You can control exactly what gets serialized:
Output:
| Original | Config{url='https://api.example.com', apiKey='sk-secret-key-123', timeout=30000} |
| [Custom writeObject | apiKey encrypted] |
| [Custom readObject | apiKey decrypted] |
| Restored | Config{url='https://api.example.com', apiKey='sk-secret-key-123', timeout=30000} |
Common Mistakes
1. Forgetting to implement Serializable
// ❌ NotSerializableException at runtime!
class MyClass {
// missing: implements Serializable
}
// ✅ Always implement Serializable
class MyClass implements Serializable { }2. Non-serializable fields
// ❌ If a field's class isn't Serializable, the whole object fails
class DataHolder implements Serializable {
private Socket connection; // Socket isn't Serializable → Exception!
}
// ✅ Mark non-serializable fields as transient
class DataHolder implements Serializable {
private transient Socket connection; // Excluded from serialization
}3. Not declaring serialVersionUID
// ❌ JVM generates one automatically — breaks if class changes
class MyClass implements Serializable { }
// ✅ Always declare explicitly
class MyClass implements Serializable {
private static final long serialVersionUID = 1L;
}Interview Questions
Q1: What is serialization in Java?
Answer: Serialization is the process of converting a Java object into a byte stream so it can be persisted to a file, sent over a network, or stored in a database. The reverse process (byte stream → object) is deserialization.
Q2: What is the Serializable interface? Why is it called a marker interface?
Answer: Serializable is an interface with NO methods. It's called a "marker" interface because it simply marks/tags a class as eligible for serialization. The JVM checks for this marker before allowing serialization.
Q3: What is the transient keyword?
Answer: transient marks a field to be excluded from serialization. During deserialization, transient fields receive their default values (null for objects, 0 for numbers, false for booleans). Use it for sensitive data (passwords), derived values, or non-serializable fields (connections, threads).
Q4: What is serialVersionUID and why is it important?
Answer: It's a version number for the serialized class. During deserialization, JVM compares the sender's UID with the receiver's. If they don't match, it throws InvalidClassException. Declaring it explicitly allows controlled class evolution (adding fields without breaking existing serialized data).
Q5: What happens if a parent class is not Serializable but the child is?
Answer: Only the child's fields are serialized. During deserialization, the parent's no-argument constructor is called to initialize parent fields. If the parent doesn't have a no-arg constructor, deserialization fails with InvalidClassException.
Q6: Can static fields be serialized?
Answer: No. Static fields belong to the class, not to any instance. Serialization saves instance state only. However, serialVersionUID (which is static) is a special case used by the serialization mechanism itself.
Exam Focus
Revise definitions, diagrams, examples, and short-answer points for Serialization in Java.
Interview Use
Prepare one clear explanation, one practical example, and one common mistake for this Java Master Course topic.
Search Terms
java-master-course, java master course, java, master, course, file, handling, serialization
Related Java Master Course Topics