skip to content

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

level: middleimportance: should knowfreq 55%

answer

  1. Statics are class-level, not instance-level
  2. Serialization = one object's state
  3. Static value reflects current JVM, not save time
  4. transient on static is redundant
  5. serialVersionUID is metadata, not serialized data

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.

solid answer

~40 s

Static fields are not serialized by default. Serialization captures the state of one object instance, and a static field belongs to the class — it is shared by all instances and lives in the class metadata, not in any object. So when ObjectOutputStream walks an object's fields it skips both static and transient ones. A practical consequence: if you serialize an object, change the static field's value, then deserialize, the deserialized object 'sees' the current static value in this JVM, not the value at serialization time, because the static was never part of the stream. If you genuinely need to persist class-level state you must handle it manually (e.g. in writeObject/readObject, or serialize a holder instance). This often surprises people who expect a static counter or config to round-trip.

code

java · 12 lines
java
class Counter implements Serializable {
    private static final long serialVersionUID = 1L;
    static int total = 1;   // class-level: NOT serialized
    int id;                  // instance-level: serialized
    Counter(int id) { this.id = id; }
}

// serialize a Counter while total==1, then:
// Counter.total = 99;            // change the shared static
// Counter c = (Counter) in.readObject();
// c.id  -> restored from stream
// Counter.total -> 99 (current JVM value, the stream never held it)

go deeper

for a junior

Knows static fields are not serialized and that only instance fields are saved.

for a middle

Explains why (class-level vs instance-level) and the practical 'static reflects current JVM value, not save-time' consequence.

for a senior

Discusses serialVersionUID as class-descriptor metadata, redundancy of transient-on-static, and how to deliberately persist class state if truly required.

for a principal

Reasons about the hazards of global static state crossing serialization boundaries (overwriting JVM-wide values, multi-JVM consistency) and steers designs away from relying on it.

## Instance state vs class state Every Java field is either **instance-level** or **static (class-level)**: - An **instance field** (no `static` modifier) has a separate copy in **each object**. Two `Account` objects each have their own `balance`. - A **static field** (`static` modifier) has exactly **one copy shared by the whole class**, stored with the class metadata, not inside any object. `static int instanceCount;` is one number no matter how many objects exist. ## Why serialization skips statics Serialization is defined as capturing the **state of a single object instance** so it can be rebuilt later. A static field is not part of an instance's state — it's part of the **class's** state, shared across all instances and bound to the loaded class in a particular JVM. There is no meaningful 'this object's value' of a static field to write, so `ObjectOutputStream` **omits static fields** (along with `transient` ones) when it reflects over the fields. ## The observable consequence Because the static value isn't in the stream, deserialization does **not** restore it. The deserialized object simply reads whatever the static field currently holds in the JVM doing the read. Example: 1. `Config.version = 1;` then serialize a `Config` object. 2. Later `Config.version = 2;` (changed in this JVM). 3. Deserialize the saved object → reading `version` gives **2**, not 1. If you deserialize in a **fresh JVM** where the class is freshly loaded, the static holds whatever its initializer set (e.g. its declared default), again not the value at serialization time. ## transient + static Marking a static field `transient` is **redundant**: statics are already excluded. You'll sometimes see it, but it adds nothing. ## serialVersionUID is the exception that proves the rule The one static field that participates in serialization is `private static final long serialVersionUID` — but not as *data*. Its value isn't 'serialized as instance state'; it's written into the **class descriptor** as a version stamp and compared on read to detect incompatible class changes (mismatch → `InvalidClassException`). So it's metadata about the class, consistent with statics being class-level. ## If you must persist class-level state Default serialization won't do it. Options: explicitly read/write the static inside custom `writeObject`/`readObject` (writing `out.writeInt(counter)` etc.), or model the shared state as an instance you serialize, or store it separately (a config file, DB). But be careful: a static is global, so 'restoring' it from one deserialized object overwrites the JVM-wide value for everyone.

  • You serialize an object, change a static field, then deserialize. What value does the static hold afterward?
    The current value in the running JVM (the changed one), not the value at serialization time. The static was never written to the stream, so deserialization can't and doesn't restore it.
  • Is serialVersionUID, being static, serialized?
    Not as instance data. Its value is written into the class descriptor as a version stamp and checked on deserialization (mismatch throws InvalidClassException). It's class metadata, consistent with statics not being part of an instance's state.

Serializing an object is like photographing one tenant's apartment. The building's shared lobby (a static field) isn't in that photo — it belongs to the whole building, so every apartment 'sees' whatever the lobby looks like now, not how it looked when the photo was taken.

saying these in an interview costs you the question

  • Expecting a static counter or config to round-trip through serialization
  • Adding transient to a static field thinking it changes anything
  • Assuming deserialization restores the static value from save time
  • Confusing serialVersionUID being saved with static fields being saved as data

context