欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

五种单例设计模式以及反射攻击改进

程序员文章站 2022-03-09 21:52:32
...

饿汉式(推荐用)

  • 效率高
  • 线程安全
  • 不支持懒加载
public class MySingleClass01 {
    //私有化构造方法
    private MySingleClass01(){}
    //声明本类对象,并使用private static修饰
    private static MySingleClass01 instance = new MySingleClass01();
    //提供外部获取方法
    public static MySingleClass01 getInstance (){
        return instance;
    }
}

饿汉式

  • 效率高
  • 线程不安全
  • 支持懒加载
public class MySingleClass02 {
    //私有化构造方法
    private MySingleClass02(){}
    //声明本类对象的引用
    private static MySingleClass02 instance ;
    //提供外部获取方法
    public static MySingleClass02 getInstance (){
        if(instance==null){
            instance=new MySingleClass02();
        }
        return instance;
    }
}

静态内部类单例设计模式(推荐用)

  • 效率高
  • 线程安全
  • 支持懒加载
public class MySingleClass03 {

    private MySingleClass03(){}

    static class MySingleClassHolder{
        private static MySingleClass03 instance = new MySingleClass03();
    }

    public static MySingleClass03 getInstance(){
        return MySingleClassHolder.instance;
    }
}

同步懒汉单例设计模式

  • 效率非常低
  • 线程安全
  • 支持懒加载
public class MySingleClass04 {

    private MySingleClass04(){}

    private static  MySingleClass04 instance;

    public static MySingleClass04 getInstance(){

        synchronized (MySingleClass04.class){
            if(instance==null){
                instance=new MySingleClass04();
            }
        }
        return instance;
    }
}

双重锁单例设计模式(推荐用)

  • 效率高
  • 线程安全
  • 支持懒加载
public class MySingleClass05 {
    private MySingleClass05(){}

    private static  MySingleClass05 instance;

    public static MySingleClass05 getInstance(){

        if(instance==null){
            synchronized (MySingleClass04.class){
                if(instance==null){
                    instance=new MySingleClass05();
                }
            }
        }
        return instance;
    }
}

通过单例模式可以保证系统中,应用该模式的类一个类只有一个实例。即一个类只有一个对象实例。但是通过反射可以突破单例设计模式的唯一性。

public class demo06 {
    public static void main(String[] args) throws Exception {
        //饿汉单例设计模式
        MySingleClass01 instance01 = MySingleClass01.getInstance();
        Constructor<MySingleClass01> c1 = MySingleClass01.class.getDeclaredConstructor();
        c1.setAccessible(true);
        MySingleClass01 instance02 = c1.newInstance();
        System.out.println(instance01==instance02);
        System.out.println("------------------------------------------------------------");

        //双重锁单例设计模式
        MySingleClass05 instance3 = MySingleClass05.getInstance();
        Constructor<MySingleClass05> c2 = MySingleClass05.class.getDeclaredConstructor();
        c2.setAccessible(true);
        MySingleClass05 instance4 = c2.newInstance();
        System.out.println(instance3==instance4);
        System.out.println("------------------------------------------------------------");

        //静态内部类单例设计模式
        MySingleClass03 instance5 = MySingleClass03.getInstance();
        Constructor<MySingleClass03> c3 = MySingleClass03.class.getDeclaredConstructor();
        c3.setAccessible(true);
        MySingleClass03 instance6 = c3.newInstance();
        System.out.println(instance5==instance6);
        System.out.println("------------------------------------------------------------");
    }
}

运行后得到的结果
五种单例设计模式以及反射攻击改进
所以我们需要对这些单例设计模式做进一步的改进。使他们防止反射的攻击。这里以饿汉单例设计模式;双重锁单例设计模式;静态内部类单例设计模式为例子。

public class MySingleClass01 {

    //私有化构造方法
    private MySingleClass01(){
        if(instance!=null){
            throw new RuntimeException("已经存在对象了!");
        }
    }
    //声明本类对象,并使用private static修饰
    private static MySingleClass01 instance = new MySingleClass01();

    //提供外部获取方法
    public static MySingleClass01 getInstance (){
        return instance;
    }
}

再次使用反射,会抛出异常
五种单例设计模式以及反射攻击改进

public class MySingleClass05 {
    private MySingleClass05(){
        if(instance==null){
            throw new RuntimeException("已经存在对象了!");
        }
    }
    private static  MySingleClass05 instance;
    public static MySingleClass05 getInstance(){
        if(instance==null){
            synchronized (MySingleClass04.class){
                if(instance==null){
                    instance=new MySingleClass05();
                }
            }
        }
        return instance;
    }
}

运行后,抛错误
五种单例设计模式以及反射攻击改进

public class MySingleClass03 {
    private MySingleClass03(){
        if(MySingleClass03.getInstance()!=null){
            throw new RuntimeException("已经存在对象了");
        }
    }
    static class MySingleClassHolder{
        private static MySingleClass03 instance = new MySingleClass03();
    }
    public static MySingleClass03 getInstance(){
        return MySingleClassHolder.instance;
    }
}

运行后,抛错误
五种单例设计模式以及反射攻击改进

总结:每次创建对象,都会走无参构造器,因此在无参构造器中对对象的实例进行是否为空判断,如果是非空,就抛出异常。则可以防止反射攻击,但是无法防止序列话攻击,只有枚举可以防止序列话攻击。

相关标签: 设计模式