设计模式2——单例模式

设计模式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修饰,如果是则抛出异常,反射失败。所以枚举是不怕发射攻击的。

枚举有有参构造函数。枚举不怕反射的攻击。

原文地址:https://www.cnblogs.com/ghlz/p/13564492.html