Effective Java#77声明我们必须在序列化期间使用readResolve
来保留Singleton保证。他们使用了这个例子。
public class Elvis implements Serializable{
public static final Elvis INSTANCE = new Elvis();
private Elvis() { ... }
public void leaveTheBuilding() { ... }
他们建议使用
如果是Elvis课程 实现Serializable, 以下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; }
此方法忽略 反序列化的对象,返回 杰出的埃尔维斯实例 在课堂上创建 初始化。
答案 0 :(得分:4)
该类只加载一次(除非您使用类加载器,但实际上类不同)。对上述代码进行反序列化确实会创建一个新的Elvis
。您需要使用串行代理来避免这种情况。
虽然有两个Elvis
个实例,Elvis.INSTANCE
只指向一个。
反序列化构造一个对象而不调用执行任何可序列化类的构造函数(但它会执行最派生的非可序列化基类的no-arg构造函数)。
(顺便说一下,你没有创建你的类final
,所以即使是一个子类也可以被反序列化。顺便说一下,你提出的readResolve
方法不会被调用为子类,因为它是private
。)
答案 1 :(得分:1)
我建议在你的单例类中创建一个代理类来保存你所有的变量。然后你可以有访问函数[getProxyClass()& setProxyClass()]。使代理类可序列化,然后当你去序列化或反序列化时使用代理类,只需使用访问器函数来获取或设置它。如果你这样做,它就会减少单身类所涉及的大量混乱。
答案 2 :(得分:0)
- 现在问题是序列化是否再次加载类以拥有两个Elvis实例?
创建了一个新的Elvis实例(模仿者),但重载的readResolve
方法确保它不会作为ObjectInputStream.readObject()
返回的数据结构的一部分返回。
猫王模仿者(或很快变得)无法到达,并且被垃圾收集。
- 如果只加载一次类,那么我们应该只有一个Elvis实例,因为静态字段没有被序列化,并且在反序列化期间没有恢复,
理想情况下是的。在实践中没有。
- 其他Elvis实例从哪里获得的资格可以通过readResolve进行垃圾回收(防止转义反序列化过程)。这可以解释一下吗?
反序列化过程从创建第二个猫王(模仿者)开始,但readResolve
方法确保没有任何东西可以看到它。
要了解这种情况的原因和原因,您需要了解readResolve()
方法在反序列化中扮演的函数,如指定的here。基本上,当readResolve()
方法返回INSTANCE
时,它会说,“无论你在我们正在构建的图表中使用模仿者,都要使用真正的猫王”。