0 重点掌握
0.1 单例模式如何完全安全
首先前提必须是饿汉式单例,才有安全可能性,原因参考设计模式单例模式。
饿汉式单例的代码demo 参见本节2.5
0.2 饿汉式和懒汉式区别
参靠设计模式单例模式,一个是类加载时就初始化,一个是不初始化,static静态代码块
0.3 如何理解:本节2.2和2.1 对比的优势
工厂方法优势之一,提供了灵活性,不改变其API的前提下,可以改变该类是否应该为Singleton的想法,工厂方法返回唯一实例。
如:Enum工厂类的getInstance返回唯一实例,如果是其他工厂类可以返回非唯一实例。参考本节2.4
0.4 破坏单例的因素
1 反射
2 序列化攻击
1 课程内容
1.1 Singleton简介
Singleton指仅仅被实例化一次的类。通常代表本质上唯一的组件,如:窗口管理器或文件系统等。
1.2 用三种不同方法强化Singleton属性
参见本节2.1,2.2,2.3
1.3 三种不同方法优缺点:
- 公有静态成员为final域:
缺点:享有特权的客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用构造器。
解决:修改构造器,让它被要求创建第二个实例时抛出异常。
- 公有静态成员为静态工厂方法
缺点:每次被反序列化一个序列化的实例时,都会创建一个新的实例。
解决:实现Serializable接口,申明所有实例域都是瞬时(transient)的,提供readResolve方法。
- 单元素的枚举类型
功能上与公有域方法接近,无偿提供序列化机制,绝对防止多次实例化。
2 代码演练
2.1 实现Singleton方法1:公有静态成员为final域
package com.ddwei.test.core.chapter2.demo22; //单例 public class Elvis { public static final Elvis INSTANCE = new Elvis(); //私有构造 private Elvis(){ } public void method(){ } }
2.2 实现Singleton方法2:公有静态成员为静态工厂方法
package com.ddwei.test.core.chapter2.demo21; /** * 工厂方法生成单例 * 相比第一种,优势: * 1 改变了灵活性,不改变api的前提下就可以改变该类是否成为Singleton(它提供了更多的灵活性,在不改变api的前提下,我们可以轻易地自由调整这个类是否是singleton。工厂方法返回该类的唯一实例,但它很容易修改成别的样子,例如为每个调用该方法的线程提供唯一实例。) * 2 与泛型(27条)有关,public域的方法比较简单 * @author weidoudou * @date 2022/4/13 8:24 **/ public class Elvis { private static final Elvis INSTANCE = new Elvis(); private Elvis(){ } public static Elvis getINSTANCE() { return INSTANCE; } public void method(){ } }
2.3 只需要编写包含单元素的枚举类型,实现Singleton
package com.ddwei.test.core.chapter2.demo25; public enum Elvis { INSTANCE; public void leaveTheBuilding(){ } }
2.4 只需要编写包含单元素的枚举类型,实现Singleton 扩展(可能不适用)
部分参考自:https://blog.csdn.net/m0_38130105/article/details/84284687
单例类:
package com.ddwei.test.core.chapter2.demo24; public class SingletonClass { }
Enum类:
package com.ddwei.test.core.chapter2.demo24; //单例 public enum Elvis { INSTANCE; private SingletonClass instance; Elvis(){ instance = new SingletonClass(); } public SingletonClass getInstance(){ return instance; } public void method(){ } }
2.5 如何完全保证单例类不被破坏
package com.ddwei.test.core.chapter2.demo23; //单例 public class Elvis { public static final Elvis INSTANCE; static { INSTANCE = new Elvis(); } /** * 1 构造方法私有,针对外部对象直接new 对象,破坏单例的处理 * 2 饿汉模式,构造方法做非空判断, 针对通过反射攻击,破坏单例的处理 * @author weidoudou * @date 2022/4/13 20:30 * @param * @return null **/ //私有构造 private Elvis() { if(INSTANCE!=null){ throw new RuntimeException("单例构造器禁止反射"); } } public void method(){ } /** * 3 针对序列化和反序列化 生成对象处理,破坏单例的处理 * @author weidoudou * @date 2022/4/13 20:29 * @param * @return java.lang.Object **/ private Object readResolve(){ return INSTANCE; } }
诸葛