Effective Java #77 states that we have to use readResolve
to preserve the Singleton guarentee during serialization. They have used the example.
public class Elvis implements Serializable{
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
and they suggest using
If the Elvis class is made to
implement Serializable, the
following readResolve method suffices
to guarantee the singleton property:
// readResolve for instance control - you can do better!
private Object readResolve() {
// Return the one true Elvis and let the garbage collector
// take care of the Elvis impersonator.
return INSTANCE; }
This method ignores
the deserialized object, returning the
distinguished Elvis instance that was
created when the class was
initialized.
- Now the question is does
serialization loads the class again
to have two instance of Elvis?
- If the class is loaded only once
then we should be having only one
instance of Elvis since static
fields are not serialized and are
not restored during
deserialization and
- From where does the other Elvis
instance comes which is made
eligble for garbage collection by
readResolve (prevented from
escaping the deserializtaion
process).
Can this be explained?
The class is only loaded once (unless you muck about with class loaders, but then the classes are actually different). Deserialisation of the above code does indeed create a new Elvis
. You would need to use a serial proxy to avoid that.
Whilst there are two Elvis
instances, Elvis.INSTANCE
only points to one.
Deserialisation constructs an object without calling executing any constructors of serialisable classes (it does however execute the no-arg constructor of the most derived non-serialisable base class).
(And btw, you've not made your class final
, so even a subclass can be deserialised. And, incidentally, your proposed readResolve
method would not be called for a subclass as it is private
.)
I'd suggest creating a proxy class inside your singleton class to hold all of your variables. Then you can have accessor functions [getProxyClass() & setProxyClass()]. Make the proxy class serializable, then when you go to serialize or deserialize use the proxy class and just use the accessor functions to get or set it. If you do it this way it cuts out a lot of the mess involved with the singleton class.
- Now the question is does serialization loads the class again to have two instance of Elvis?
A new instance of Elvis is created (the impersonator), but the overloaded readResolve
method ensures that it is not returned as part of the data structure returned by ObjectInputStream.readObject()
.
The Elvis impersonator is (or soon becomes) unreachable, and is garbage collected.
- If the class is loaded only once then we should be having only one instance of Elvis since static fields are not serialized and are not restored during deserialization and
Ideally yes. In practice no.
- From where does the other Elvis instance comes which is made eligible for garbage collection by readResolve (prevented from escaping the deserialization process). Can this be explained?
The deserialization process starts out by creating the 2nd Elvis (the impersonator), but the readResolve
method ensures that nothing ever sees it.
To understand how and why that is the case, you need to understand the function that a readResolve()
method plays in deserialization, as specified here. Basically, when the readResolve()
method returns INSTANCE
it is saying, "wherever you were going to use the impersonator in the graph we are building, use the real Elvis instead".