Reputation: 2111
I got an NPE in java.util.HashSet.isEmpty() on line 191. I guess, this line just calls isEmpty() on the internal map field.
To my surprise, this field is transient, so after deserialization, it would be null. But isn't that the purpose of deserializing a set, to get the values back? To my eyes, being deserialized is the only way this field can be null for a HashSet instance.
Probably, I'm missing something here. Can someone explain?
Java 1.8.0_151 on Linux (3.13.0-61-generic) on platform amd64
Here is the implementation of HashMap.isEmpty
from the JDK:
/**
* Returns <tt>true</tt> if this set contains no elements.
*
* @return <tt>true</tt> if this set contains no elements
*/
public boolean isEmpty() {
return map.isEmpty(); // line 191
}
Edit / additional info:
isEmpty()
. But the NPE occurs in the library, so that this method was obviously called on an existing instance, i.e, not on null
. Therefore, providing this snippet would not help muchUpvotes: 1
Views: 430
Reputation: 298459
Since the map
field is not final
, there is no guarantee to see it in its initialized state when publishing a newly constructed HashSet
instance improperly in multi-threaded code. Whereas “newly constructed” means that no other action ensuring memory visibility between the involved threads has happened since the construction, which in principle may be an arbitrary long time.
During object deserialization, the readObject
method takes care of re-initializing the map
field and putting back the elements. This is necessary to hide these implementation details from the persistent form. Further, deserialized objects may have a different hash code than they had upon serializing (take the hash code inherited from java.lang.Object
, for example). So they have to be re-inserted anyway. It’s a general principle of most collections to hide the implementation details and just serialize and deserialize each contained element one after another in dedicated writeObject
and readObject
methods.
So a future HashSet
implementation could be a real hash set, not using a HashMap
behind the scenes, without affecting serialization compatibility.
Upvotes: 3