Java序列化:readObject()与readResolve()

有效的Java和其他资源提供了一个相当不错的解释,说明在使用可序列化的Java类时如何以及何时使用readObject()方法。 另一方面,readResolve()方法仍然有点神秘。 基本上我find的所有文件都只提到了其中的一个,或者只提到了两个。

尚未回答的问题是:

  • 这两种方法有什么区别?
  • 什么时候应该采用哪种方法?
  • readResolve()应该如何使用,特别是在返回什么?

我希望你能对这个问题有所了解。

readResolve用于replace从stream中读取的对象。 我见过的唯一用途是强制单身人士; 读取对象时,将其replace为单例实例。 这确保没有人可以通过序列化和反序列化单例创build另一个实例。

readObject返回之后调用readResolve (相反, writeReplacewriteObject之前调用,可能在不同的对象上)。 该方法返回的对象this对象replace为返回给ObjectInputStream.readObject的用户以及对该stream中的对象的任何更后面的引用。 它主要用于串行代理(参见Effective Java,2nd Ed,IIRC)。

ObjectInputStream从stream中读取一个对象并准备将其返回给调用者时,将调用readResolve方法。 ObjectInputStream检查对象的类是否定义了readResolve方法。 如果方法已定义,则调用readResolve方法以允许stream中的对象指定要返回的对象。 返回的对象应该是与所有用途兼容的types。 如果不兼容,则发现types不匹配时将抛出ClassCastException

readResolve可以用来改变通过readObject方法序列化的数据。 例如,xstream API使用此function来初始化一些不在XML中的属性,以反序列化。

http://x-stream.github.io/faq.html#Serialization

readResolve适用于您可能需要返回现有对象的情况,例如因为您正在检查应该合并的重复input,或者(例如,在最终一致的分布式系统中),因为这是在您意识到之前可能到达的更新任何旧版本。

readResolve()将确保序列化时的单例合同。
参阅

readResolve方法

对于Serializable和Externalizable类,readResolve方法允许一个类在返回给调用者之前replace/parsing从stream中读取的对象。 通过实现readResolve方法,一个类可以直接控制自己被反序列化的实例的types和实例。 该方法定义如下:

ANY-ACCESS-MODIFIER对象readResolve()抛出ObjectStreamException;

ObjectInputStream从stream中读取一个对象并准备将其返回给调用者时,将调用readResolve方法。 ObjectInputStream检查对象的类是否定义了readResolve方法。 如果方法已定义,则调用readResolve方法以允许stream中的对象指定要返回的对象。 返回的对象应该是与所有用途兼容的types。 如果不兼容,则发现types不匹配时将抛出ClassCastException

例如,可以创build一个Symbol类,其中每个符号绑定的单个实例只存在于虚拟机中。 将执行readResolve方法来确定该符号是否已被定义,并replace先前存在的等效Symbol对象以维护身份约束。 通过这种方式,Symbol对象的唯一性可以在序列化中保持不变。

当序列化被用来转换一个对象,以便它可以保存在文件中,我们可以触发一个方法,readResolve()。 该方法是私有的,并保存在同一个类中,在反序列化的同时对象正在被检索。 它确保了在反序列化之后,返回的对象与序列化的一样。 即, instanceSer.hashCode() == instanceDeSer.hashCode()

readResolve()方法不是一个静态方法。 在反序列化的时候调用in.readObject()之后,它只是确保返回的对象与下面序列化的那个一样out.writeObject(instanceSer)

 .. ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file1.ser")); out.writeObject(instanceSer); out.close(); 

这样,它也有助于单例devise模式的实现,因为每次都返回相同的实例。

 public static ABCSingleton getInstance(){ return ABCSingleton.instance; //instance is static } 

readObject()是ObjectInputStream类中的一个已有方法。在反序列化时读取对象readObject方法在内部检查被反序列化的类对象是否具有readResolve方法,如果readResolve方法存在,那么它将调用readResolve方法并返回相同实例。

所以写readResolve方法的强度是一个很好的实践,实现纯粹的单例devise模式,没有人可以通过序列化/反序列化来获得另一个实例。