码迷,mamicode.com
首页 > 编程语言 > 详细

Java设计模式--单例模式

时间:2020-04-25 17:03:30      阅读:69      评论:0      收藏:0      [点我收藏+]

标签:包含   inf   构造   核心   好处   style   com   lse   不能   

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

 

单例模式的分类:

1.饿汉式:

饿汉式,从名字上也很好理解,就是“比较饿”,实例在初始化的时候就已经建好了,不管你有没有用到,都先建好了再说。好处是没有线程安全的问题,坏处是浪费内存空间。

技术图片技术图片

 

 2.懒汉式:

懒汉式,顾名思义就是实例在用到的时候才去创建,“比较懒”,用的时候才去检查有没有实例,如果有则返回,没有则新建。单线程情况下不会出现问题,但是在多线程情况下会存在线程安全问题。但仅仅只是采用synchronized锁来保证是不够的,必须要加上双重校验锁和volatile关键字对实例进行修饰。volatile关键字主要是保证内存可见性的(关于内存模型相关内容),因为对象的创建并不是原子性操作。

技术图片

3.静态内部类:

静态内部类的方式效果类似双检锁,但实现更简单。但这种方式只适用于静态域的情况,双检锁方式可在实例域需要延迟初始化时使用。

技术图片

 

 

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

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

它的定义是这样的:

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

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

技术图片

 

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

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

技术图片

 

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

技术图片

 

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

技术图片

 

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

技术图片

 

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

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

技术图片

 

 结果如下:

技术图片

 

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

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

技术图片

 

 

 

 

 结果是:

技术图片

 

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

那如何解决呢?

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

技术图片

 

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

我们试下:

技术图片

 

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

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

技术图片

 

 我们修改下:

技术图片

 

 技术图片

 

 运行结果:

技术图片

 

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

 

Java设计模式--单例模式

标签:包含   inf   构造   核心   好处   style   com   lse   不能   

原文地址:https://www.cnblogs.com/lonelystreet/p/12773524.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!