有效的 Java 项目 #77 - 单例对象的序列化 - 为什么我必须使用 readResolve?

tut*_*ara 1 java singleton serialization

《Effective Java #77》规定,我们必须readResolve在序列化过程中使用单例保证。他们已经使用了这个例子。

public class Elvis implements Serializable{
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
Run Code Online (Sandbox Code Playgroud)

他们建议使用

如果Elvis类实现了Serialized,下面的readResolve方法足以保证单例属性:

// 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; }
Run Code Online (Sandbox Code Playgroud)

此方法忽略反序列化的对象,返回类初始化时创建的杰出 Elvis 实例。

  • 现在的问题是序列化是否再次加载该类以获得两个 Elvis 实例?
  • 如果该类仅加载一次,那么我们应该只有一个 Elvis 实例,因为静态字段不会序列化,并且在反序列化期间不会恢复,并且
  • 另一个 Elvis 实例从哪里来,它有资格通过 readResolve 进行垃圾收集(防止逃避反序列化过程)。这可以解释一下吗?

Tom*_*ine 5

  • 该类仅加载一次(除非您对类加载器进行了修改,但这些类实际上是不同的)。上述代码的反序列化确实创建了一个新的Elvis. 您需要使用串行代理来避免这种情况。

  • 虽然有两个Elvis实例,Elvis.INSTANCE但仅指向一个。

  • 反序列化构造一个对象,而不调用执行可序列化类的任何构造函数(但是它执行最派生的不可序列化基类的无参数构造函数)。

(顺便说一句,你还没有创建你的类final,所以即使是子类也可以反序列化。而且,顺便说一句,你提出的readResolve方法不会被子类调用private。)