skip to content

Serializable & transient

Serializable is a marker that switches on default serialization, transient excludes a field, and statics are never serialized because they belong to the class. Interviewers ask what transient is for, usually in the context of passwords or caches.

part ofJavaoverview, primer and where to startread it →
on this pageshow

questions

5

What is the Serializable interface in Java, and what does implementing it actually do?

level: juniorimportance: must knowfreq 70%

answer

  1. Marker interface, no methods
  2. ObjectOutputStream/ObjectInputStream
  3. Whole object graph, recursive
  4. NotSerializableException at runtime
  5. serialVersionUID controls versioning

basics

~10 s

Serializable is an empty interface a class implements to say its objects can be turned into bytes and back. It has no methods; it just marks the class as allowed to be serialized.

solid answer

~40 s

Serializable is a marker interface (it declares no methods) in java.io. Implementing it tells the JVM that instances may be converted into a byte stream by ObjectOutputStream and reconstructed by ObjectInputStream. Serialization captures the object graph: the object's non-transient, non-static instance fields, recursively following references, so every referenced object must also be Serializable or you get a NotSerializableException at runtime. Because it's a marker, you write no code for default behavior; the JVM uses reflection. You should also declare a serialVersionUID so versioning is explicit. It is used to persist objects to disk, send them over a network (RMI), or cache them, though modern systems often prefer JSON/Protobuf for cross-platform safety.

code

java · 20 lines
java
import java.io.*;

class Point implements Serializable {
    private static final long serialVersionUID = 1L;
    int x, y;
    Point(int x, int y) { this.x = x; this.y = y; }
}

public class Demo {
    public static void main(String[] args) throws Exception {
        Point p = new Point(3, 4);
        try (var out = new ObjectOutputStream(new FileOutputStream("p.ser"))) {
            out.writeObject(p);            // serialize
        }
        try (var in = new ObjectInputStream(new FileInputStream("p.ser"))) {
            Point q = (Point) in.readObject(); // deserialize
            System.out.println(q.x + "," + q.y); // 3,4
        }
    }
}

go deeper

for a junior

Knows Serializable is an empty marker interface, that you add 'implements Serializable', and that ObjectOutputStream/ObjectInputStream do the work.

for a middle

Explains the object-graph recursion, NotSerializableException, the role of serialVersionUID, and that transient/static fields are excluded.

for a senior

Discusses versioning compatibility, when to prefer JSON/Protobuf, security risks of deserializing untrusted input, and that the constructor is bypassed.

for a principal

Frames serialization in system design: format choice for evolution and interop, deserialization attack surface and mitigations (allowlists, ObjectInputFilter), and why Java serialization is largely discouraged for new external boundaries.

## What serialization is **Serialization** is converting an in-memory Java object into a flat sequence of **bytes** so it can be stored (file, DB) or transmitted (network) and later **deserialized** — reconstructed into an equivalent object. Think of flattening a structure into a ribbon you can mail, then unfolding it on the other side. ## The Serializable interface `java.io.Serializable` is a **marker interface**: an interface with **no methods and no fields**. A marker interface exists only to *tag* a class with metadata the runtime checks. By writing `class Foo implements Serializable`, you assert "instances of Foo may be serialized." You add **no code** — the JVM provides the default behavior automatically. ## How the default mechanism works You serialize with **`ObjectOutputStream`** and its `writeObject(obj)` method, and read back with **`ObjectInputStream`** and `readObject()`. Under the hood the JVM uses **reflection** to walk the object's fields: - It writes the class descriptor (class name, `serialVersionUID`, field metadata). - It writes each **instance field** that is **not `transient`** and **not `static`**. - For each field that is itself an object reference, it recursively serializes that object too. This is the **object graph**: a tree/graph of all reachable objects. Shared references and cycles are handled by a back-reference table, so the same object isn't written twice and cycles don't loop forever. ## Why every referenced object must be Serializable If the graph reaches an object whose class does **not** implement `Serializable`, serialization fails at runtime with **`java.io.NotSerializableException`**, naming the offending class. There is no compile-time check — `Serializable` has no methods to force, so the requirement is verified only when you actually serialize. ## serialVersionUID Each serializable class has a `serialVersionUID` — a long that identifies the class version. If you don't declare one, the compiler generates it from the class structure; any structural change produces a different value, and deserializing old bytes throws `InvalidClassException`. Best practice: declare `private static final long serialVersionUID = 1L;` explicitly so you control compatibility. ## What it does NOT serialize Default serialization skips **`transient`** fields and **`static`** fields (statics belong to the class, not the instance). Constructors are **not** run on deserialization — the object is rebuilt directly from bytes via reflection. ## When to use / avoid Use it for quick JVM-to-JVM persistence, caching, or legacy RMI. Avoid it for untrusted input (deserializing attacker-controlled bytes is a major security risk — gadget-chain RCE) and for cross-language or long-term formats, where JSON, Protobuf, or Avro are safer and more portable.

  • What happens if a serializable class references an object whose class is not Serializable?
    Serialization throws java.io.NotSerializableException at runtime, naming that class. There's no compile-time check because Serializable has no methods. Fix it by making the referenced class Serializable or marking that field transient.
  • Does deserialization call the constructor?
    No. The object is reconstructed via reflection from the byte stream; no constructor of the serializable class runs. (The no-arg constructor of the first non-serializable superclass IS invoked, however.)

Serializable is like a 'this parcel may be shipped' sticker — it carries no instructions, it just authorizes the postal system (the JVM) to flatten and box the contents.

saying these in an interview costs you the question

  • Thinking Serializable has methods you must implement
  • Believing it does a compile-time check that the whole graph is serializable
  • Assuming static fields are saved
  • Thinking the constructor runs on deserialization
  • Ignoring serialVersionUID and being surprised by InvalidClassException

context

open as a page

What does the transient keyword do during serialization, and when would you use it?

level: middleimportance: must knowfreq 68%

basics

~10 s

transient marks an instance field to be skipped during serialization. Its value is not written out, and after deserialization it comes back as the default for its type (0, false, or null).

open as a page

Are static fields serialized by Java's default serialization? Explain why.

level: middleimportance: should knowfreq 55%

basics

~10 s

No. Default serialization saves only instance fields. Static fields belong to the class, not to any single object, so there is nothing instance-specific to write, and they aren't included in the byte stream.

open as a page

What is serialVersionUID, and what goes wrong if you don't declare it?

level: seniorimportance: should knowfreq 58%

basics

~20 s

serialVersionUID is a version number for a serializable class. If you don't declare one, the compiler generates it from the class structure; any change creates a new value, so old saved bytes can no longer be read and you get InvalidClassException.

open as a page

Why is deserializing untrusted data with Java's built-in serialization dangerous, and what mitigations exist?

level: principalimportance: should knowfreq 45%

basics

~20 s

Reading objects from untrusted bytes lets an attacker control what classes get instantiated and which methods run during deserialization, which can lead to remote code execution. Don't deserialize untrusted input; prefer safe formats like JSON, or filter allowed classes.

open as a page