序列化单例模式的实现————readResolve 源码解读 | Java Debug 笔记

本文正在参加「Java主题月 – Java Debug笔记活动」,详情查看 活动链接

上篇提到了这个序列化单例模式,这篇就来探究下它的源码啦,感觉它是挺特殊的一种单例 哈哈?

序列化单例模式的实现————readResolve 源码解读

在可序列化类中加上readResolve方法,就可以实现单例模式了!这是为什么呢?让我们一起看看源码中的奥秘吧!

只有实现了序列化接口 Serializable ,才可以进行 序列化操作,

测试代码

class SingletonTest {

  

  */***

   ** 序列化测试公共方法*

   *** *@param* *className*

   **/*

   private void testSerializable(String className) {

    if (className == null) {

      throw new RuntimeException("className不能为null");

    }

    Class<?> clazz = null;

    Object obj = null;

    try {

      clazz = Class.forName(className);

      Method method = clazz.getMethod("getInstance");

      obj = method.invoke(null);

    } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {

      e.printStackTrace();

    }

    int lastIndexOf = className.lastIndexOf(".");

    String realName = className.substring(lastIndexOf + 1);

    String objName = realName + ".obj";

    Object s1 = null;

    Object s2 = obj;



    FileOutputStream fileOutputStream = null;

    try {

      fileOutputStream = new FileOutputStream(objName);

      ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);

      objectOutputStream.writeObject(s2);

      objectOutputStream.flush();

      objectOutputStream.close();

      FileInputStream fileInputStream = new FileInputStream(objName);

      ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);

      Object o = objectInputStream.readObject();

      s1 = o;

      objectInputStream.close();



      System.out.println(s1);

      System.out.println(s2);

      System.out.println(s1 == s2);





    } catch (IOException | ClassNotFoundException e) {

      e.printStackTrace();

    }

  }



  */***

   ** 序列化单例模式l*

   **/*

  @Test

  void testSerializableSingleton() {

    testSerializable("com.example.demo.singleton.SerializableSingleton");

  }



}
复制代码

序列化单例模式【测试】

先注释掉下面的代码

20200912111157

执行 testSerializableSingleton 方法,结果如下图,序列化和反序列化出来的不是同一个对象,违背了单例模式,也就是说,在这种情况下通过序列化模式可以破坏单例模式.

20200912111254


源码

readObject

接着我们来看看为什么要加上面注释掉的代码,

进入 Object o = objectInputStream.readObject();

20200912114821

进入上面红框中的方法 readObject0,它是readObject的底层实现方法,

在该方法中中找到下图

20200912114941

readOrdinaryObject

来到上图中的方法readOrdinaryObject,继续往下看

20200912114531

这里会去判断有没有这个无参构造器,有的话obj不为null,会执行下图中的代码

20200912115229

这里会去判断有没有这个 hasReadResolveMethod ,有的话会通过反射方法

invokeReadResolve去创建这个对象,最后将obj的引用地址指向当前创建的对象rep,最后 return 出去。

invokeReadResolve

我们来看看invokeReadResolve做了什么

20200912115745

通过注释可知,它会去调用所表示的可序列化类的 readResolve 方法,在idea中通过通过ctrl+鼠标左键点击readResolveMethod方法,选择getInheritableMethod可以看到下图

20200912120232

20200912120643

了解到该方法是一个 参数argTypes为空,返回类型为 Object的函数,那他的修饰符(modifier)是什么呢?

20200912121044

可以知道该方法如果是 static 或者 ABSTRACT 就直接返回 null

抽象方法没有方法体,它需要非抽象子类去实现它,就直接返回null了,

那为什么static也返回null呢!希望看到该博文的大神们帮忙答疑!!?谢谢!!

这个我想了好久也想不出答案来。。 直到我重新看到它的方法名 getInheritableMethod:获取可以继承的方法?

猜测:
  1. static方法修饰后它就属于类了,无法被重写,也无法在使用时动态绑定了,如:class A 实现了序列化接口,并定义了readResolve 方法,class B 和 C 都继承了 A ,此时反序列化B,反序列化的过程会去调用这个invokeReadResolve方法,通过该方法进行反射调用,如果readResolve 方法是static 这时会找不到该方法的。?

对猜测进行验证,弄一个简单的继承关系测试下!如图:

20201214081918

输出结果如下图:

解析:很明显这里 getDeclaredMethods 是获取不到任何方法的,因为这个只能获取到 B 自己声明的一些方法。

而源码中(上上张图?)是通过这个getDeclaredMethod 方法去获取的!通过反射的知识点我们知道,该方法只能获取该类自己定义的方法。

20201214081835

其他访问修饰符也是符合对应的权限才会返回该方法的。

如下表:

修饰符 当前类 同包 子类 不同包
public Y Y Y Y
protected Y Y Y N
default Y Y N N
private Y N N N

我是 4ye 我们下期再见啦 ヾ( ̄▽ ̄)ByeBye

欢迎关注,交个朋友呀!! ( •̀ ω •́ )y

嘿嘿 喜欢就支持下啦 ?

让我们开始这一场意外的相遇吧!~

欢迎留言!谢谢支持!ヾ(≧▽≦*)o

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享