← Back to Home

Deserialization

Deserialization is the reverse process of serialization. It converts a byte stream back into a live Java object, restoring the object’s state exactly as it was at the time of serialization.

This is a high-frequency interview topic, usually asked together with serialization, transient, and serialVersionUID.

What Is Deserialization?

  • Converts byte stream → Java object
  • Reconstructs object state from serialized data
  • Uses ObjectInputStream
  • Creates a new object in memory

Why Deserialization Is Needed

  • Restore objects from files
  • Receive objects over network
  • Reload cached objects
  • Session restoration in applications

Deserialization Flow (Conceptual)

Serialized File / Network Stream
          ↓
ObjectInputStream.readObject()
          ↓
New Java Object (state restored)
          

Basic Deserialization Example

Serializable Class

import java.io.Serializable;

class Employee implements Serializable {
    int id;
    String name;

    Employee(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
          

Deserialization Code

ObjectInputStream ois =
    new ObjectInputStream(new FileInputStream("emp.ser"));

Employee e = (Employee) ois.readObject();
ois.close();

System.out.println(e.id + " " + e.name);

✔ Object recreated
✔ Same state as during serialization
✔ Constructor NOT called
          

Key Rules of Deserialization (Interview Critical)

  1. Class must implement Serializable
  2. serialVersionUID must match
  3. Constructors are NOT executed
  4. Static fields are NOT restored
  5. Transient fields get default values
  6. New object is created in heap

What Happens to Different Fields?

Field Type Deserialization Behavior
Instance variable Restored
transient Default value (null, 0, false)
static Not restored
final Restored (if serialized)

serialVersionUID and Deserialization (Very Important)

private static final long serialVersionUID = 1L;
          

If serialVersionUID Mismatch

java.io.InvalidClassException
          
  • ✔ Same UID → success
  • ❌ Different UID → failure

Parent Class Behavior (Interview Trap)

Case 1: Parent is Serializable

  • Parent fields are restored
  • Parent constructor NOT called

Case 2: Parent is NOT Serializable

  • Parent no-arg constructor IS called
  • Parent fields initialized normally

Custom Deserialization (Advanced)

Override readObject() for custom logic.

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {

    ois.defaultReadObject();
    // custom validation / logic
}
          

✔ Used for:

  • Validation
  • Decryption
  • Reinitializing transient fields

Deserialization Security Risks (Real-World)

  • Malicious serialized data
  • Arbitrary code execution
  • Object injection attacks

Mitigation

  • Never deserialize untrusted data
  • Validate object state
  • Use filtering (ObjectInputFilter)
  • Prefer JSON/XML for APIs

Serialization vs Deserialization (Quick Compare)

Aspect Serialization Deserialization
Direction Object → Stream Stream → Object
Main class ObjectOutputStream ObjectInputStream
Constructor called ❌ No ❌ No
Purpose Save / send Restore

Common Beginner Mistakes

  • Expecting constructor to run
  • Forgetting serialVersionUID
  • Assuming transient values restore
  • Deserializing untrusted data
  • Class mismatch between serialize/deserialize

Interview-Ready Answers

Short Answer

Deserialization converts a byte stream back into a Java object.

Detailed Answer

In Java, deserialization is the process of reconstructing an object from its serialized byte stream using ObjectInputStream. It restores the object’s state without invoking constructors and requires the class to implement Serializable with a compatible serialVersionUID.

Key Takeaway

Deserialization restores object state, not object behavior. Understand constructor behavior, transient fields, and UID compatibility to avoid runtime failures and security issues.

Deserialization Interview Cheatsheet

1. Basic Deserialization

import java.io.*;

class Demo {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois =
            new ObjectInputStream(new FileInputStream("user.ser"));

        User u = (User) ois.readObject();
        System.out.println(u.id + " " + u.name);
        ois.close();
    }
}
          

2. Deserialization Order Matters

Object obj1 = ois.readObject();
Object obj2 = ois.readObject();
          

Explanation

Must read in same order as written.

3. transient Field After Deserialization

class User implements Serializable {
    int id;
    transient String password;
}

// After deserialization
password == null
          

4. static Field After Deserialization

class Demo implements Serializable {
    static int x = 10;
}
          

Explanation

static value comes from class, not stream.

5. serialVersionUID Match (Successful Deserialization)

class User implements Serializable {
    private static final long serialVersionUID = 1L;
}
          

Result

Class changes allowed (within compatibility).

6. serialVersionUID Mismatch (Failure)

// Change class structure without matching UID
          

Exception

InvalidClassException

7. Deserializing Inherited Object (Parent Serializable)

class Parent implements Serializable {
    int x = 10;
}

class Child extends Parent {
    int y = 20;
}

Child c = (Child) ois.readObject();
          

Result

Both x and y restored.

8. Parent NOT Serializable, Child Serializable

class Parent {
    int x = 10;
}

class Child extends Parent implements Serializable {
    int y = 20;
}
          

Result

x reset using parent no-arg constructor.

y restored from stream.

9. Custom Deserialization (readObject)

class User implements Serializable {
    transient String password;

    private void readObject(ObjectInputStream ois) throws Exception {
        ois.defaultReadObject();
        password = "recovered";
    }
}
          

10. Deserializing ArrayList

import java.io.*;
import java.util.*;

class Demo {
    public static void main(String[] args) throws Exception {
        ObjectInputStream ois =
            new ObjectInputStream(new FileInputStream("list.ser"));

        ArrayList<String> list =
            (ArrayList<String>) ois.readObject();

        System.out.println(list);
        ois.close();
    }
}
          

11. Deserializing Multiple Objects

User u1 = (User) ois.readObject();
User u2 = (User) ois.readObject();
          

Rule

Same order as serialization.

12. Deserialization with try-with-resources

try (ObjectInputStream ois =
         new ObjectInputStream(new FileInputStream("a.ser"))) {
    Object obj = ois.readObject();
}
          

13. ClassNotFoundException Trap

try {
    ois.readObject();
} catch (ClassNotFoundException e) {
    System.out.println("Class missing");
}
          

Why

.class not found in classpath.

14. Object Graph Restoration

class Order implements Serializable {
    User user;
}

Order o = (Order) ois.readObject();
          

Explanation

Entire object graph restored.

All referenced objects must be serializable.

15. Deserialization with Cast Safety

Object obj = ois.readObject();
if (obj instanceof User) {
    User u = (User) obj;
}
          

16. Deserializing After JVM Restart

// Works because data stored in .ser file
          

Interview Point

Independent of JVM lifecycle.

17. Default Values After Deserialization

int x;        // 0
String s;     // null
boolean b;    // false
          

When

Field not serialized (transient / parent field).

18. Security Trap (Untrusted Source)

// Never deserialize untrusted data
          

Risk

Remote code execution.

Gadget attacks.

19. Deserialization vs Constructor

// Constructor is NOT called during deserialization
          

Exception

Non-serializable parent constructor is called.

20. Interview Summary – Deserialization

ObjectInputStream.readObject()
          

Key Points

  • Byte stream → object
  • Constructor not invoked
  • transient → default value
  • UID must match
  • Order matters
  • All referenced objects must be serializable