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

饿汉式(推荐用)

  • 效率高
  • 线程安全
  • 不支持懒加载
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;
    }
}

运行后,抛错误
在这里插入图片描述

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值