为了账号安全,请及时绑定邮箱和手机立即绑定

【九月打卡】第13天+ 单例模式讲解 三

标签:
设计模式

课程名称:Java设计模式精讲 Debug方式+内存分析

课程章节:第8章 单例模式讲解+Coding+源码解析

主讲老师:Geely

课程内容:

饿汉模式实现单例?

/**

* 饿汉式 : 比较饿,类加载的时候就初始化。

* 懒加载:调用才创建对象。

* 饿汉式:类加载就创建对象。

*/

public class HungrySingleton {

private static HungrySingleton _hungrySingleton_ = new HungrySingleton();

public static HungrySingleton getInstance(){

return _hungrySingleton_;

}

private HungrySingleton(){}

}

问题1)饿汉式和懒加载的区别?

饿汉式就是很饿,加载类就创建对象,懒加载只有调用的时候才初始化。

饿汉式是类加载就初始化。(如果始终都没用到该对象,会浪费资源。)

懒加载是被引用的时候初始化。(延迟加载,调用之后初始化)

类加载初始化的内容。决定了饿汉式还是懒汉式。

类加载分为三个步骤:加载,连接,初始化(这个初始化,只会初始化代码块和成员变量)

问题2)避免反射和反序列化带来的破坏?

枚举就是通过常量访问变量:

使用枚举创建一个对象:

1是枚举内部类,2是枚举常量(这里是一个值,访问的时候,是通过枚举类名.常量)

3是枚举变量 4是枚举类的构造函数。5是给枚举变量赋值(这个值是通过枚举常量来访问。)

6是通过一个方法返回实例,7是该类的私有构造函数,防止外部创建该类的实例。

使用反射,看创建的对象是否一致?发现反射的对象和直接获取的对象是一致的。

**Class clazz = EnumStarvingSingleton.****class;**

**Constructor constructor = clazz.getDeclaredConstructor()****;**

**constructor.setAccessible(****true****)****;**

**EnumStarvingSingleton enumStarvingSingleton = (EnumStarvingSingleton)constructor.newInstance()****;**

**System.**_**out**_**.println(enumStarvingSingleton.**_**getInstance**_**())****;**

  

使用反射直接获取枚举的对象。从而获取对应的实例。

其实反序列化也会创建多个对象。通过枚举类型创建单例是如何避免反序列化创建多个对象呢?

首先将类进行序列化存储,之后进行反序列化,就可以创建多个对象。但是通过枚举,反序列化也会创建一个对象。是通过

反编译工具:jad

先通过javac编译生成对应class 文件。

再通过jad class文件全路径。就会生成jad文件。

问题3)枚举类型的定义和使用方式?

枚举分为:

  1. 常量部分

  2. 变量部分。

  3. 构造函数。

  4. Get/set返回常量值。

例子1:

public enum MyDay {

**MONDAY(1,"星期一"),THUSDAY(2,"星期二");//这个后面必须有分号**

**private int code;**

**private String name;**

**private MyDay(int code,String name) {**

**this.code = code;**

**this.name = name();**

**}**

public int getCode() {

return code;

}

public String getName() {

return name;

}

public void setCode(int code) {

this.code = code;

}

public void setName(String name) {

this.name = name;

}

}

  

  

**例如2:**

**public**  **enum** **Color {**

**RED,BLANK,YELLOW**

**}**

**使用**

**System.out.println(Color.BLANK);**

  

问题4)double check和volatile的作用?

进行第二次判空的原因是,有两个线程同时通过了第一次判断,第一个线程创建了对象,释放了锁,第二个线程获取锁,如果不判断,还会再创建一个对象。

使用volatile的原因是,new 的时候是分三步,第三步和第二步因为不存在依赖关系,所以可以发送排序,也就是先让instance指向了内存空间,该内存空间还未进行初始化,就会让其他线程获取到null的情况。所以使用volatile避免重排序。

注意:无论饿汉模式,还是懒汉模式。都可以通过反射获取到类的实例。也就是通过反射重新创建一个对象。

问题5)使用Java9,设计单例模式?

在cpu中的指令:A,B不能重排序,C,D之间也不可以重排序,也就是在当前volatile的作用域内,所有的指令是不允许做重排序。

使用setRelease也是为了防止重排序,它能够仅仅防止当前语句重排序,不会防止它前后的语句重排序。

例如:它可以让A,B 之间重排序,可以让C,D之间重排序,但是不允许A,B和C,D之间有重排序

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消