以一个简陋的单例模式举例:
1 | public class SerializableTest implements Serializable { |
将构造器设置为 private 权限,使用 static 和 final,这样运行中获得的实例都应是同一个对象,但是使用序列化/反序列话时,这将被打破。如下:
1 | ObjectOutputStream oou = new ObjectOutputStream(new FileOutputStream("serializable.a")); |
此时将输出false,也就是说反序列化读入的对象与原对象不是同一个。
为了解决这个问题,我们在 SerializableTest 类中添加一个 readResolve() 方法,返回我们希望的对象,如下:
1 | protected Object readResolve() throws ObjectStreamException { |
我们在 readResolve() 方法返回我们希望的实例,这样再次运行,将输出true,反序列化得到的是原来的对象。
readResolve() 不是重写的父类方法,也不是实现的接口的方法,不难想到这是用反射实现。
debug一下可以追踪到,在 ObjectInputStream 类的 readOrdinaryObject(boolean unshared) 方法有以下代码:
1 | if (obj != null && |
再继续,可以看到 invokeReadResolve(Object obj) 方法有以下代码:
1 | requireInitialized(); |
也就是说,以上的“单例模式”,以及常用的双重校验锁等,在反序列化的情况下会构建出新的对象,添加 readResolve() 方法可以在反序列化时保持单例。