面试问题:关于 Java 序列化和单例 [已关闭]

2022-09-01 15:11:24

在一次采访中,面试官问了我以下问题:是否可以序列化单例对象?我说是的,但是在什么情况下我们应该序列化单例?

是否可以设计一个对象无法序列化的类?


答案 1

这个问题可能应该更好地表述为“是否可以以不破坏单例模式的方式将序列化和反序列化与单例模式类C一起使用?

答案基本上是肯定的:

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());
    }
}

但请注意,使用此代码可能存在多个实例。但是,只引用了一个。其他的符合垃圾回收的条件,仅由反序列化运行时创建,因此它们不存在于实际目的。AppState

有关其他两个问题的答案(在哪种情况下,我们应该序列化单例?有没有可能设计一个对象不能序列化的类?),参见@Michael Borgwardt的答案


答案 2

在哪种情况下,我们应该序列化单例。

想象一下,你有一个长时间运行的应用程序,并希望能够关闭它,然后在它被关闭的地方继续(例如,为了进行硬件维护)。如果应用使用有状态的单例,则必须能够保存和还原 sigleton 的状态,这可以通过序列化它来轻松完成。

是否可以设计一个对象无法序列化的类。

确实很简单:只是不要实现并创建类Serializablefinal