设计模式2——单例模式
饿汉式:
package com.ghl.single;
/**
* @ProjectName DesignPattern
* @ClassName Hungry
* @Date 2020/8/25 15:42
* @Author gaohengli
* @Version 1.0
*/
//饿汉式单例
public class Hungry {
//可能会浪费空间
private byte[] data1=new byte[1024*1024];
private byte[] data2=new byte[1024*1024];
private byte[] data3=new byte[1024*1024];
private byte[] data4=new byte[1024*1024];
//私有化构造函数
private Hungry() {
}
//设立静态变量,直接创建实例
private static final Hungry HUNGRY = new Hungry();
//开放公有方法,判断是否已存在实例
public static Hungry getInstance(){
return HUNGRY;
}
}
懒汉式:
package com.ghl.single;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
/**
* @ProjectName DesignPattern
* @ClassName LazyMan
* @Date 2020/8/25 16:01
* @Author gaohengli
* @Version 1.0
*/
//DCL懒汉式单例
public class LazyMan {
private static boolean flag = false;
//私有化构造器
private LazyMan() {
/*//解决反射破坏单例的问题
synchronized (LazyMan.class) {
if (lazyMan != null) {
throw new RuntimeException("不要试图用反射破坏异常");
}
}*/
synchronized (LazyMan.class) {
if (flag==false){
flag=true;
}else {
throw new RuntimeException("不要试图用反射破坏异常");
}
}
}
//volatile可见性,禁止指令重排序
private volatile static LazyMan lazyMan;
//双重检测锁模式的懒汉式单例,DCL懒汉式
public static LazyMan getInstance() {
if (lazyMan == null) {
synchronized (LazyMan.class) {
if (lazyMan == null) {
lazyMan = new LazyMan();//不是一个原子性操作
/*
1.分配内存空间
2.执行构造方法,初始化对象
3.把这个对象执行这个空间
*/
}
}
}
return lazyMan;
}
/*//多线程并发
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
new Thread(()->{
LazyMan.getInstance();
}).start();
}
}*/
//反射,会破坏单例
public static void main(String[] args) throws Exception {
//LazyMan instance = LazyMan.getInstance();
Field flag = LazyMan.class.getDeclaredField("flag");
flag.setAccessible(true);
Constructor<LazyMan> declaredConstructor = LazyMan.class.getDeclaredConstructor(null);
declaredConstructor.setAccessible(true);//破坏私有权限
LazyMan instance = declaredConstructor.newInstance();
flag.set(instance,false);
LazyMan instance1 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
静态内部类:
package com.ghl.single;
/**
* @ProjectName DesignPattern
* @ClassName Holder
* @Date 2020/8/25 17:10
* @Author gaohengli
* @Version 1.0
*/
//静态内部类实现
public class Holder {
private Holder(){
}
public static Holder getInstance(){
return InnerClass.HOLDER;
}
//静态内部类
public static class InnerClass{
private static final Holder HOLDER=new Holder();
}
}
*前面的单例模式都不安全,因为反射可以破解,因此下面使用枚举。
枚举单例模式:
package com.ghl.single;
import java.lang.reflect.Constructor;
/**
* @ProjectName DesignPattern
* @ClassName EnumSingle
* @Date 2020/8/25 17:35
* @Author gaohengli
* @Version 1.0
*/
//enum,枚举,本身也是一个Class类
public enum EnumSingle {
INSTANCE;
public EnumSingle getInstance(){
return INSTANCE;
}
}
class Test{
public static void main(String[] args) throws Exception {
EnumSingle instance = EnumSingle.INSTANCE;
//Exception in thread "main" java.lang.NoSuchMethodException: com.ghl.single.EnumSingle.<init>()
//Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(null);
Constructor<EnumSingle> declaredConstructor = EnumSingle.class.getDeclaredConstructor(String.class,int.class);
declaredConstructor.setAccessible(true);
EnumSingle instance1 = declaredConstructor.newInstance();
System.out.println(instance);
System.out.println(instance1);
}
}
检测枚举时结果会报Exception in thread "main" java.lang.NoSuchMethodException。出现这个异常的原因是因为EnumSingleton.class.getDeclaredConstructors()获取所有构造器,会发现并没有我们所设置的无参构造器,只有一个参数为(String.class,int.class)构造器,而且在反射在通过newInstance创建对象时,会检查该类是否ENUM修饰,如果是则抛出异常,反射失败。所以枚举是不怕发射攻击的。
枚举有有参构造函数。枚举不怕反射的攻击。