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

简介: 序列化单例模式的实现————readResolve 源码解读在可序列化类中加上readResolve方法,就可以实现单例模式了!这是为什么呢?让我们一起看看源码中的奥秘吧!只有实现了序列化接口 Serializable ,才可以进行 序列化操作,测试代码class SingletonTest { */*** ** 序列化测试公共方法* *** *@param* *className* **/* private void testSerializable(String className) { if (className =

序列化单例模式的实现————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");
  }
}
复制代码



序列化单例模式【测试】


先注释掉下面的代码


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


源码

readObject


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


进入 Object o = objectInputStream.readObject();


网络异常,图片无法展示
|


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

在该方法中中找到下图


网络异常,图片无法展示
|


readOrdinaryObject


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


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


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


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


rep,最后 return 出去。


invokeReadResolve


我们来看看invokeReadResolve做了什么


网络异常,图片无法展示
|


通过注释可知,它会去调用所表示的可序列化类的 readResolve 方法,在idea中通过


通过ctrl+鼠标左键点击readResolveMethod方法,选择getInheritableMethod


可以看到下图


网络异常,图片无法展示
|


网络异常,图片无法展示
|


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


网络异常,图片无法展示
|


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


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


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


这个我想了好久也想不出答案来。。 直到我重新看到它的方法名


getInheritableMethod:获取可以继承的方法🙃


猜测:


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


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


网络异常,图片无法展示
|


输出结果如下图:


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


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


网络异常,图片无法展示
|


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


如下表:


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



目录
相关文章
|
1月前
|
设计模式 存储 负载均衡
【五】设计模式~~~创建型模式~~~单例模式(Java)
文章详细介绍了单例模式(Singleton Pattern),这是一种确保一个类只有一个实例,并提供全局访问点的设计模式。文中通过Windows任务管理器的例子阐述了单例模式的动机,解释了如何通过私有构造函数、静态私有成员变量和公有静态方法实现单例模式。接着,通过负载均衡器的案例展示了单例模式的应用,并讨论了单例模式的优点、缺点以及适用场景。最后,文章还探讨了饿汉式和懒汉式单例的实现方式及其比较。
【五】设计模式~~~创建型模式~~~单例模式(Java)
|
22天前
|
设计模式 安全 Java
Java 单例模式,背后有着何种不为人知的秘密?开启探索之旅,寻找答案!
【8月更文挑战第30天】单例模式确保一个类只有一个实例并提供全局访问点,适用于需全局共享的宝贵资源如数据库连接池、日志记录器等。Java中有多种单例模式实现,包括饿汉式、懒汉式、同步方法和双重检查锁定。饿汉式在类加载时创建实例,懒汉式则在首次调用时创建,后者在多线程环境下需使用同步机制保证线程安全。单例模式有助于提高代码的可维护性和扩展性,应根据需求选择合适实现方式。
29 1
|
24天前
|
SQL 设计模式 安全
Java编程中的单例模式深入解析
【8月更文挑战第27天】本文旨在探索Java中实现单例模式的多种方式,并分析其优缺点。我们将通过代码示例,展示如何在不同的场景下选择最合适的单例模式实现方法,以及如何避免常见的陷阱。
|
20天前
|
设计模式 安全 Java
Java编程中的单例模式深度解析
【8月更文挑战第31天】 单例模式,作为设计模式中的经典之一,在Java编程实践中扮演着重要的角色。本文将通过简洁易懂的语言,逐步引导读者理解单例模式的本质、实现方法及其在实际应用中的重要性。从基础概念出发,到代码示例,再到高级应用,我们将一起探索这一模式如何优雅地解决资源共享和性能优化的问题。
|
20天前
|
设计模式 安全 Java
Java中的单例模式:理解与实践
【8月更文挑战第31天】在软件设计中,单例模式是一种常用的设计模式,它确保一个类只有一个实例,并提供一个全局访问点。本文将深入探讨Java中实现单例模式的不同方法,包括懒汉式、饿汉式、双重校验锁以及静态内部类等方法。每种方法都有其适用场景和潜在问题,我们将通过代码示例来展示如何根据具体需求选择合适的实现方式。
|
20天前
|
设计模式 安全 Java
Java编程中的单例模式实现与应用
【8月更文挑战第31天】在Java的世界里,单例模式是构建高效且资源友好应用的基石之一。本文将深入浅出地介绍如何通过单例模式确保类只有一个实例,并提供一个全局访问点。我们将探索多种实现方法,包括懒汉式、饿汉式和双重校验锁,同时也会讨论单例模式在多线程环境下的表现。无论你是Java新手还是资深开发者,这篇文章都将为你打开一扇理解并有效应用单例模式的大门。
|
30天前
|
设计模式 SQL 缓存
Java编程中的设计模式:单例模式的深入理解与应用
【8月更文挑战第22天】 在Java的世界里,设计模式是构建可维护、可扩展和灵活的软件系统的基石。本文将深入浅出地探讨单例模式这一经典设计模式,揭示其背后的哲学思想,并通过实例演示如何在Java项目中有效运用。无论你是初学者还是资深开发者,这篇文章都将为你打开一扇洞悉软件设计深层逻辑的大门。
26 0
|
1月前
|
设计模式 SQL 安全
单例模式大全:细说七种线程安全的Java单例实现,及数种打破单例的手段!
设计模式,这是编程中的灵魂,用好不同的设计模式,能使你的代码更优雅/健壮、维护性更强、灵活性更高,而众多设计模式中最出名、最广为人知的就是Singleton Pattern单例模式。通过单例模式,我们就可以避免由于多个实例的创建和销毁带来的额外开销,本文就来一起聊聊单例模式。
|
2月前
|
设计模式 安全 Java
Java面试题:什么是单例模式?如何在Java中实现单例模式?
Java面试题:什么是单例模式?如何在Java中实现单例模式?
30 0
|
2月前
|
设计模式 安全 Java
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
Java面试题:解释单例模式的实现方式及其优缺点,讨论线程安全性的实现。
24 0