简体   繁体   English

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

[英]Effective Java Item #77 - Serialization of singleton objects - Why should I have to use readResolve?

Effective Java #77 states that we have to use readResolve to preserve the Singleton guarentee during serialization. 有效的Java #77指出,在序列化期间,我们必须使用readResolve来保留Singleton保证人。 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: 如果使Elvis类实现了Serializable,则以下readResolve方法足以保证singleton属性:

// 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. 此方法忽略反序列化的对象,返回在初始化类时创建的独特的Elvis实例。

  • Now the question is does serialization loads the class again to have two instance of Elvis? 现在的问题是序列化是否再次将类加载到具有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 如果该类仅加载一次,则我们应该只有Elvis的一个实例,因为静态字段不会序列化,并且在反序列化和
  • From where does the other Elvis instance comes which is made eligble for garbage collection by readResolve (prevented from escaping the deserializtaion process). 另一个Elvis实例来自哪里,通过readResolve(避免转义反序列化过程来防止垃圾回收)使它有资格进行垃圾收集。 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 . 上面代码的反序列化确实创建了一个新的Elvis You would need to use a serial proxy to avoid that. 您将需要使用串行代理来避免这种情况。

  • Whilst there are two Elvis instances, Elvis.INSTANCE only points to one. 虽然有两个Elvis实例,但Elvis.INSTANCE只指向一个。

  • 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). 反序列化可以构造一个对象,而无需调用执行可序列化类的任何构造函数(但是,它确实执行最派生的不可序列化基类的no-arg构造函数)。

(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 .) (顺便说一句,您还没有将您的类定型为final ,因此即使子类也可以反序列化。而且,顺便提一句,因为子类是private ,所以不会为子类调用您建议的readResolve方法。)

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()]. 然后,您可以具有访问器函数[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? 现在的问题是序列化是否再次将类加载到具有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() . 创建了Elvis的新实例(模拟程序),但是重载的readResolve方法确保不将其作为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 如果该类仅加载一次,则我们应该只有Elvis的一个实例,因为静态字段不会序列化,并且在反序列化和

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). 另一个Elvis实例从哪里来,通过readResolve(防止转义反序列化过程避免)使该实例有资格进行垃圾回收。 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. 反序列化过程通过创建第二个Elvis(模仿者)开始,但是readResolve方法确保没有人看到它。

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 . 要了解如何以及为什么是这样的话,你要明白,一个功能readResolve()方法在反序列化发挥,作为指定在这里 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". 基本上,当readResolve()方法返回INSTANCE它的意思是:“无论您打算在我们要创建的图形中使用模拟器的任何地方,都应使用真实的Elvis”。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Effective in Java Item 89: For instance control, prefer enum types to readResolve - 为什么窃取者可以更改原始实例的字段? - Effective in Java Item 89: For instance control, prefer enum types to readResolve - Why can the stealer change the field of the original instance? Java序列化readResolve方法和kryo - Java serialization readResolve method and kryo Java序列化:readResolve()的访问修饰符 - Java serialization: access modifier for readResolve() 为什么我应该在Java中使用序列化而不是文件I / O - Why should i use Serialization instead of File I/O in java Java 序列化:readObject() 与 readResolve() - Java serialization: readObject() vs. readResolve() 每次在对象的序列化之前和序列化之后获得相同的哈希码,而不使用Java中的readResolve方法,为什么? - Getting same hashcode every time before serialization and after seriadeserialization of object without using readResolve method in Java why? java servlet中的spymemcached-我应该使用单例吗? - spymemcached in a java servlet - should I use a singleton? 有效的java项目编号74(关于序列化):明智地实现Serializable - Effective java Item no 74(on serialization): Implement Serializable judiciously 用readResolve()序列化静态字段 - Serialization of static fields with readResolve() 对于不需要序列化,代理或修饰的bean,我应该使用CDI javax.inject.Singleton吗? - Should I Use CDI javax.inject.Singleton for the beans that dont need serialization, proxies, or decorations
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM