设计模式 | 挑战单例模式(五)


theme: channing-cyan

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

内容接着上篇文章《挑战单例模式(四)》,上篇文章讲到了静态内部类单例实现方式,这篇文章不讲实现,我们理性分析地我们实现的所有的单例是否真的就高枕无忧了,这篇讲反射对单例的破坏,以及解决方案。

七、反射破坏单例

在上面实现的单例所有方式中,虽然从正常情况下,因为构造方法是私有的,对象实例的流程通过不同的方式保证只会进行一次。但凡事都不要太绝对啦,有一种特殊的利器可以避开正常的对象构造方法,那就是反射

Java反射是什么,它是一组API,提供了用于在运行时检查或修改方法、类或接口的方法。反射为我们提供了关于对象所属类的信息,以及可以通过使用对象执行的类的方法;通过反射,我们可以在运行时调用方法,而不用考虑方法的访问权限。所以总的来说,我们可以通过反射获取对象所属的类的名称对象的构造函数方法及其方法描述(注释等)

我们借用第三章实现的懒汉式单例模式SingletonInLazy类,使用反射实例化对象。

public class ReflectDestroysSingleton {   public static void main(String[] args) {       //好事者干的好事       final Class<SingletonInLazy> clazz = SingletonInLazy.class;       //通过反射获取私有构造方法       final Constructor<SingletonInLazy> declaredConstructor;       try {           declaredConstructor = clazz.getDeclaredConstructor(null);           //强制性访问           declaredConstructor.setAccessible(true);           //进行两次实例化           final SingletonInLazy instance1 = declaredConstructor.newInstance();           final SingletonInLazy instance2 = declaredConstructor.newInstance();           System.out.println(instance1 == instance2);       } catch (NoSuchMethodException e) {           e.printStackTrace();       } catch (InvocationTargetException e) {           e.printStackTrace();       } catch (InstantiationException e) {           e.printStackTrace();       } catch (IllegalAccessException e) {           e.printStackTrace();       }   } }

运行结果为false。很显然,这个例子我们通过反射技术创建了两个不同的实例。通过这种方式,不可访问的私有构造函数变得可访问,并且使类成为单例的的目标被破坏。那么怎么来挽救一下呢?

方法很简单,在私有构造方法里面抛异常

public class UpgradeSingletonInLazy { ​   private UpgradeSingletonInLazy() {       if(INSTANCE != null){           throw new AssertionError();       }       System.out.println("----------私有构造方法实例化完成---------");       INSTANCE = this;   } ​   public static UpgradeSingletonInLazy INSTANCE = null;   static final Runnable RUNNABLE = () -> {       final UpgradeSingletonInLazy instance = UpgradeSingletonInLazy.getInstance();       System.out.println(Thread.currentThread().getName() + ":" + instance);   }; ​   public static UpgradeSingletonInLazy getInstance() {       if (INSTANCE == null) {           INSTANCE = new UpgradeSingletonInLazy();       }       return INSTANCE;   } }

再次运行上面反射测试例子,结果如下。

反射.png

确实解决了反射对单例的破坏,但是代码逻辑冗长,不够优雅!如何解决呢?答案是使用注册式单例

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值