readResolve()原理

从序列化中恢复一个单例对象会破坏单例模式,解决方法是添加readResolve()

原理:

  1. 反序列化时,首先获取序列化的类 : desc( 可理解为单例类的class类,但它和JVM加载到内存中的单例class类有不同)因为如果我们的单例类在构造方法中通过实例不为空则抛出异常防止了反射破坏单例,那单例类是不允许再实例化的。而desc类却依然可以实例化。(当我们反序列化一个对象时,永远不会调用其类的构造函数,反序列化后的实例变量与序列化之前的实例变量相同,类变量与当前的类变量相同,如果反序列化时类未被加载则类变量为默认值。)
  2. 判断对象是否能实例化。可以则进行实例化,至此单例类进行了第一次实例化,对象名为obj
  3. 第一次实例化完成后,通过反射寻找该单例类中的readResolve()方法,没有则直接返回obj对象。(这就是直接反序列化破坏单例模式的原因)
  4. 有定义readResolve()方法,desc通过invokeReadResolve(Object obj)方法调用readResolve()方法获取单例对象instance,将他赋值给rep,如果单例对象之前已经被实例化过,那么rep就会指向之前实例化的单例对象。如果我们之前没有实例化单例对象,则rep会指向null。
  5. rep与obj进行比较,由于obj是反射获取的对象,当然与rep不等,于是将rep的值instance赋值给obj,将obj返回,返回对象instance也就保证了单例。

简而言之就是,当我们通过反序列化readObject()方法获取对象时会去寻找readResolve()方法,如果该方法不存在则直接返回新对象,如果该方法存在则按该方法的内容返回对象,以确保如果我们之前实例化了单例对象,就返回该对象如果我们之前没有实例化单例对象,则会返回null

おすすめ

転載: blog.csdn.net/qq_39304851/article/details/115823991