开发者

Interview question: about Java serialization and singletons [closed]

开发者 https://www.devze.com 2023-01-02 04:57 出处:网络
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references,or ex开发者_如何学运维pertise, but this question will likely
As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or ex开发者_如何学运维pertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance. Closed 11 years ago.

In an interview the interviewer asked me the following question: is it possible to serialize a singleton object? I said yes, but in which scenario should we serialize a singleton?

And is it possible to design a class whose object can not be serialized?


The question should probably be better phrased as "is it possible to use serialization and deserialization with a singleton-pattern class C in a way that does not break the singleton pattern?"

The answer is basically yes:

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.Serializable;

public class AppState implements Serializable
{
    private static AppState s_instance = null;

    public static synchronized AppState getInstance() {
        if (s_instance == null) {
            s_instance = new AppState();
        }
        return s_instance;
    }

    private AppState() {
        // initialize
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        synchronized (AppState.class) {
            if (s_instance == null) {
                // re-initialize if needed

                s_instance = this; // only if everything succeeds
            }
        }
    }

    // this function must not be called other than by the deserialization runtime
    private Object readResolve() throws ObjectStreamException {
        assert(s_instance != null);
        return s_instance;
    }

    public static void main(String[] args) throws Throwable {
        assert(getInstance() == getInstance());

            java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
            java.io.ObjectOutputStream oos = new java.io.ObjectOutputStream(baos);
            oos.writeObject(getInstance());
            oos.close();

            java.io.InputStream is = new java.io.ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(is);
            AppState s = (AppState)ois.readObject();
            assert(s == getInstance());
    }
}

but note that it is possible for multiple instances of AppState to exist using this code. However, only one is referenced. The others are eligible for garbage collection, created only by the deserialization runtime, so they don't exist for practical purposes.

For answers to your other two questions (In which scenario should we serialize a singleton? Is it possible to design a class whose object can not be serialized?), see @Michael Borgwardt's answer.


in which scenario we should serialize a singleton.

Imagine you have a long-running app and want to be able to shut it down and later continue at the point where it was shut down (e.g. in order to do hardware maintenance). If the app uses a singleton that is stateful, you'd have to be able to save and restore the sigleton's state, which is most easily done by serializing it.

And is it possible to design a class whose object can not be serialized.

Very simple indeed: just don't implement Serializable and make the class final


is it possible to serialize a singleton object?

It depends on how the singleton is implemented. If your singleton is implemented as an enum type with one element, then it is by default:

// Enum singleton - the preferred approach
public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding() { ... }
}

If your singleton is not implemented using a single-element enum type but, say using a static factory method (the variant is to use a public static final field):

// Singleton with static factory
public class Elvis {
    private static final Elvis INSTANCE = new Elvis();
    private Elvis() { ... }
    public static Elvis getInstance() { return INSTANCE; }
    public void leaveTheBuilding() { ... }
}

Then it is not sufficient to add implements Serializable to make it serializable, you must declare all instance fields transient (to prevent a serialization attack) and provide a readResolve method.

To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve method (Item 77). Otherwise, each time a serialized instance is deserialized, a new instance will be created, leading, in the case of our example, to spurious Elvis sightings. To prevent this, add this readResolve method to the Elvis class:

// readResolve method to preserve singleton property
private Object readResolve() {
     // Return the one true Elvis and let the garbage collector
     // take care of the Elvis impersonator.
    return INSTANCE;
}

This is heavily discussed in Effective Java (which also shows the serialization attack):

  • Item 3: Enforce the singleton property with a private constructor or an enum type
  • Item 77: For instance control, prefer enum types to readResolve

in which scenario should we serialize a singleton

For example for temporary, short-term storage or for transporting objects over a network (with RMI, for example).

And is it possible to design a class whose object can not be serialized.

As others said, don't implement Serializable. And even if an object or one of its superclasses implements Serializable, you can still prevent it from being serialized by throwing a NotSerializableException from writeObject().


i said yes

Not by default. Next to implementing java.io.Serializable you need to override readObject() and writeObject() readResolve() methods, because you cannot serialize static fields. A singleton holds its instance in a static field.

but in which scenario we should serialize a singleton.

No useful real world scenario comes to mind actually. A singleton usually doesn't change of state throughout its lifetime nor contains any state which you'd like to save/restore. If it did, then it was already wrong to make it a singleton.

Two real world examples of singleton pattern in Java SE API are java.lang.Runtime#getRuntime() and java.awt.Desktop#getDesktop(). None of them implements serializable. It also doesn't make any sense because they right returns the right/desired/expected instance on every call. If you serialize and deserialize, you may end up with multiple instances. If you switch from environment in meanwhile, the instance may not work at all.

And is it possible to design a class whose object can not be serialized.

Yes. Just don't let the class implement java.io.Serializable interface.


The problem with serializing a singleton is that you end up with two, the original and the deserialized copy.

The most obvious way to prevent serialization is to simply not implement serializable. However, sometimes you will want your singleton to implement serializable so that it can be referenced in a serialized object without issues.

If that is a problem, you have a few options. The best is to make the singleton a single member enum, if possible. that way the underlying Java implementation takes care of all the details.

If that is not possible, then you need to implement the appropriate readObject and writeObject methods to ensure that serialization does not make a separate copy.


A class that is serializable can be instantiated by deserializing it, allowing for multiple instances, making it not a singleton.

to your second question, from the java doc for java.io.Serializable

Serializability of a class is enabled by the class implementing the java.io.Serializable interface.

So to implement a class which is not serializable, don't implement Serializable.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号