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

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

  • 相关阅读:
    cmd设置代理
    移动端坐标定位tap
    T02-Django基本应用结构
    支持向量机算法的Sklearn完整复现
    T01-何为Django,入门"Hello World"
    决策树算法的Sklearn完整复现
    逻辑回归算法的Sklearn完整复现
    线性回归算法Sklearn完整复现
    K-近邻算法的Sklearn完整复现
    数据分析中的'疑难杂症'小结(三)
  • 原文地址:https://www.cnblogs.com/ghlz/p/13564492.html
Copyright © 2011-2022 走看看