Reading Objects with ObjectInputStream
ObjectOutputStream is optimized to avoid writing the same object more than once; on a second encounter it writes only a reference to the first occurrence.
Try it: Names and Objects
How Python variables are names bound to objects: assignment never copies, mutating a list is seen through every name that points at it, and ints are replaced rather than changed.
How it works
- name = object binds a name; b = a makes b point at the same object.
- Mutating a list (append, +=) changes the one shared object.
- a = a + [x] and y = y + 1 create NEW objects and re-point one name.
- Passing a list to a function passes the reference, so the function can change it.
Default run (7 steps): Two names, one list. Every name is a label that points at an object. … Printed: [1, 2, 3] / True
Simplified: Six fixed scripts on a tiny heap; you choose the values. Object numbers are illustrative, not real id() values.
Loading the simulation…
A Surprise When You Write Twice
Imagine you write a student object to a stream, change that student's grade, and write the same object again. Most people expect the stream to record the new grade. After all, the stream simply receives an object, so why would it care what the object looked like earlier? The answer is that ObjectOutputStream does not treat every write as a fresh, independent copy of the object's current contents. It has a built-in optimization that changes what happens on a second write, and that optimization is the source of a limitation every stream user must understand.
What do you think happens?
You write a student object with grade 80, change its grade to 95, and write the same object again. When the file is read back, what grade does the reader see?
Reveal answer
grade 80
The stream does not write the new contents on the second write. It writes only a reference back to the first occurrence, so the reader gets the first recorded version. The stream gives no error to signal this.
Tracing the First and Second Writes
Follow what happens when the same object is passed to writeObject twice. On the first write, the stream meets an object it has not handled before, so it serializes that object's contents into the output. On the second write, the stream recognizes the object as one it has already handled. It does not serialize the contents again. Instead, it writes only a reference pointing back to the first occurrence. The diagram below traces these two calls and the output each one produces.
Notice that the second entry in the stream is not a second copy of the student. It is a pointer to the earlier entry. The output stays smaller, and the stream avoids redundant work when the same object appears more than once in what is written.
Why the Stream Remembers Identity, Not Current State
The optimization works on identity. When the stream meets an object it has already handled, it checks whether that is the same object, and if so it does not serialize the contents again. The key consequence is that the stream remembers the object by its earlier occurrence, not by its present state. If the object has changed in the meantime, the reference still points to the first recorded version, and the new data never reaches the stream.
A back-reference is the short entry an ObjectOutputStream writes, in place of an object's contents, when that same object has already been written earlier in the stream. It points to the first occurrence rather than repeating the data.
Modifying an Object Between Two Writes
The following illustration is generated for teaching purposes. Suppose a class stores a student's name and grade in ordinary, changeable fields. Write one student object, update its grade, and write that same object again. The diagram compares the state before the second write with the state after it, and marks what differs.
Predicting the stored version
A student object is created with grade 80 and written to the stream. Its grade is then changed to 95, and the same object is written again. What version does the reader recover for the second write?
- 1Step 1: first write
The stream has not seen this object before, so it writes the full contents, including grade 80.
- 2Step 2: modify the object
The object in memory now holds grade 95. Nothing is written to the stream at this point, so the stream's record is unchanged.
- 3Step 3: second write
The stream recognizes the object from the first write and writes only a reference to that first occurrence. The new grade 95 is never serialized.
- 4Step 4: reading back
The reader follows the reference to the first record, so the object it rebuilds carries grade 80.
The reader sees grade 80 for the second write, even though the object in memory had grade 95 when it was written again.
Why Immutable Objects Suit the Stream
Because of the reuse behavior described above, ObjectOutputStreams are meant mainly for use with immutable objects. An immutable object cannot change between writes, so the first recorded version is always the correct version, and reusing a reference to it does no harm. The source's example of an immutable object is the String class, which cannot change after it is created.
An immutable design removes the trap entirely. Because the contents cannot be altered after construction, a cached reference never holds stale state, so the question of a stale copy never arises. A mutable object, by contrast, can be changed after its first write, and its earlier recorded version may then disagree with what the program believes the object is.
Forcing a Full Write with reset()
Sometimes you genuinely need to write a mutable object, and you may write the same object more than once. The source gives a direct remedy: call the stream's reset() method before writing the object. Calling reset() ensures that the full, correct version of the object is written, rather than a reference to an earlier occurrence. The following Java sketch is generated for illustration. It uses a Student class with a setGrade method and an output stream already opened on a file.
- The first
writeObjectserializes the full object because the stream has not seen it before. setGradechanges the object in memory only; the stream is not told about the change.reset()makes the second write carry the current contents instead of a back-reference.- Without the
reset()call, the secondwriteObjectwould store only a reference to the grade 80 record.
The second write now lands in the stream as complete data, carrying grade 95. The reset() call does not change the object itself. It changes what the stream does on the next write, so the record reflects the object's current state.
Mistakes When Reusing Mutable Objects
The following mistakes come from the same root cause: the stream remembers the first occurrence of an object, not its later state.
Common mistake Assuming a second writeObject records the object's new contents
What it looks likeWrite a student with grade 80, change the grade to 95, then write the same student again.
Why it failsOn the second write the stream writes only a reference to the first occurrence, so the new grade is not stored.
Do this insteadCall reset() before the second write when the object may have changed and must be stored in full.
Common mistake Expecting an error when the stored data is out of date
Why it failsThe stream gives no error to signal that the data it holds is stale, so the problem stays hidden until the data is read back.
Do this insteadTreat any re-written mutable object as a possible stale record, and check the reading side against the expected current state.
Common mistake Relying on the reset() call for an object that is never written twice
Why it failsreset()only matters when an object is encountered again. Calling it without a reason adds noise to the code without changing the output for a single write.Do this insteadUse reset() specifically before rewriting a mutable object that has changed.
Practice: Predict the Stored Version
A program writes a Student object with grade 70 to an ObjectOutputStream, then sets the grade to 88 and calls writeObject on the same object again with no reset() call. Without running the code, state what grade the reader recovers from the second write and explain why. Then describe the single change that would make the second write store grade 88.
Hints
- Ask whether the second write stores the contents or a reference.
- Think about what the stream remembers: identity or current state.
- The fix is a call that tells the stream to stop reusing the earlier occurrence.
Key Takeaways
ObjectOutputStreamavoids writing the same object twice. On a second encounter it writes only a reference to the first occurrence.- Because the stream remembers an object by identity rather than by current state, changes made between writes are not recorded, and the stream gives no error.
- ObjectOutputStreams are meant mainly for immutable objects such as String, since their first recorded version is always correct.
- For a mutable object that may be written more than once, call
reset()before writing so the full, current version is stored.