java 单例模式什么意思_Java设计模式--单例模式

单例模式,顾名思义只能存在一个实例。类中包含访问对象唯一的方法,不需要外界去实例化,可以直接访问。单例模式的核心点--构造方法私有化。

单例模式的分类:

1.饿汉式:

饿汉式,就是表面的意思“非常饿",当类进行实例化的时候就会去创建,不会存在线程安全问题。但是缺点就是,对内存的损耗比较大。

7bc406a3154723edcdbd073a767bfdd5.png

68f724bad5a33d9a9f6bd2ca7369ecb7.png

2.懒汉式:

懒汉式,有点延迟加载的意思,就是在你使用的时候才会去创建。单线程情况下不会出现问题,但是在多线程情况下会存在线程安全问题。但仅仅只是采用synchronized锁来保证是不够的,必须要加上双重校验锁和volatile关键字对实例进行修饰。volatile关键字主要是保证内存可见性的(关于内存模型相关内容),因为对象的创建并不是原子性操作。

d2c125b4270e9f6c00bba79115fddfab.png

3.静态内部类:

静态内部类,意思就是在类中创建内部类,当你使用的时候去有静态内部类来产生。

eaa3fa9830aa31fe3563939a28947217.png

单例模式的类型就这么几种,但是回过头来再看下之前的后两种类型,它们这样写就真的安全吗?答案当然是否定的。

在我们学过的技术中有一个很牛逼的,它就是反射(Java高级特性)。

它的定义是这样的:

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

它能够调用任意的方法和属性,也就意味着通过反射去获取对象就会破化单例模式。

65c2e82ad1198b502f0cb97ad59136ea.png

如果采用上图所示的方法去创建实例,instance和instance2是不同的。

那如何去解决呢?我们可以进行这样的操作:

440190d6ebe067a65915e4510d0e36d9.png

在创建实例时增加判断,加上之前懒汉式中的两重,也就是三重判断。结果如下:

e308330661ea9b0e795479f636902209.png

但是,这样是不是就解决了?不,还没有。

54303bfab77065f4e03a9d525bdde193.png

如果我们都采用反射创建对象呢?

f2dde938d2856e2f1f7f3f75efd56f85.png

实例对象又被破坏了。-_- -_- -_-

想想还有什么办法呢?--红绿灯(就是定义一个boolean值,初始为false,有则变为true,创建时进行判断)

69e182b526a28f95712affa288fb50bc.png

结果如下:

82d62267032a03d513a4cfadf6cd45bf.png

这样总该解决了吗?然而,并没有。

反射可以获取任意的属性的,当然也能修改了。

68fcd69c32c82ece012f8a28160bee01.png

结果是:

37c8b8ad42b5c68f9db962adc408da9a.png

真是道高一尺,魔高一丈啊!!

那如何解决呢?

这时候我们就要去看下源码了。

659b6400a553b1702df71b0cdcd44cea.png

在源码中我们可以看到,使用枚举来实现单例,才不会被破坏。

我们试下:

d27105a44aa4fe1698072e89253d4e93.png

好像是不能被破坏,但是注意下,提示信息和源码中的不一致。怎么回事呢?

原来是构造方法的问题,我们从idea中看到编译后的结果是无参构造,但其实不对,利用反编译工具,反编译后:

e1e1b255595b9608c1a3737eba30668e.png

我们修改下:

b60965aa8be444626d74514dcf07fd2e.png

fa2f5cefb89fb24d289b96f0d725727c.png

运行结果:

588b37d676914f524012ab494cf5959f.png

可以看到,与源码中的一致了,到这里我们才算是真正解决了这一问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值