[英]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实例。
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.