三种单例模式的终极写法(包括反射攻击)

一、饿汉式的反射攻击及解决方法

public class HungrySingleton {

	//直接声明一个需要被单例的对象,在静态块中初始化对象
    private final static HungrySingleton hungrySingleton;

    static {
        hungrySingleton=new HungrySingleton();
    }
    //私有的构造器,不被外部所访问
    private HungrySingleton(){
    	// 防止反射攻击
    	if(hungrySingleton !=null ){
    		throw new RuntimeException("单例构造器进制通过反射调用。。。。");
    	}
    	// 防止反射攻击
    }
    //提供一个外部获取HungrySingleton对象的静态方法
    public static HungrySingleton getInstance(){
        return hungrySingleton;
    }
}
public class HungryTest {
	public static void main(String[] args) {
        try {
            /** 
            * @Description: 通过反射获取对象
            * @Author: xz
            * @Date: 2020/5/31 21:06
            */ 
            //获取class对象
            Class<HungrySingleton> hungrySingletonClass = HungrySingleton.class;
            //通过获取的class对象,获取声明的构造器
            Constructor<HungrySingleton> declaredConstructor =  hungrySingletonClass.getDeclaredConstructor();
            //去除构造器的私有权限
            declaredConstructor.setAccessible(true);
            //通过构造器创建对象
            
            HungrySingleton newInstance = declaredConstructor.newInstance();
            /** 
            * @Description:  直接通过类名.getInstance方法获取对象
            * @Author: xz
            * @Date: 2020/5/31 21:07
            */ 
            HungrySingleton instance=HungrySingleton.getInstance();

            //输出2个对象,并判断是否相等
            System.out.println(newInstance);
            System.out.println(instance);
            System.out.println(newInstance==instance);

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }  catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

 

二、静态内部类的反射攻击及解决方法

public class StaticInnerClassSingleton {
	
	    //私有的构造器,不被外部所访问
	    private StaticInnerClassSingleton(){
	    	// 方式反射攻击
	    	 if(InnerClass.staticInnerClassSingleton !=null){
	    	      throw new RuntimeException("单例构造器进制反射调用");
	    	 }
	    	// 方式反射攻击
	    }
	    //私有的静态内部类
	    private static class InnerClass{
	        //new一个私有的静态的StaticInnerClassSingleton对象
	        private static StaticInnerClassSingleton staticInnerClassSingleton=new StaticInnerClassSingleton();
	    }
	    //提供一个公用的对外暴露的方法
	    public static StaticInnerClassSingleton getInstance(){
	        //返回值为通过静态内部内调用静态成员
	        return InnerClass.staticInnerClassSingleton;
	    }
}
public static void main(String[] args) {
        try {
            /**
             * @Description: 通过反射获取对象
             * @Author: xz
             * @Date: 2020/5/31 21:06
             */
            //获取class对象
            Class<StaticInnerClassSingleton> staticInnerClassSingletonClass = StaticInnerClassSingleton.class;
            //通过获取的class对象,获取声明的构造器
            Constructor<StaticInnerClassSingleton> declaredConstructor = staticInnerClassSingletonClass.getDeclaredConstructor();
            //去除构造器的私有权限
            declaredConstructor.setAccessible(true);
            //通过构造器创建对象

            StaticInnerClassSingleton newInstance = declaredConstructor.newInstance();
            /**
             * @Description:  直接通过类名.getInstance方法获取对象
             * @Author: xz
             * @Date: 2020/5/31 21:07
             */
            StaticInnerClassSingleton instance=StaticInnerClassSingleton.getInstance();

            //输出2个对象,并判断是否相等
            System.out.println(newInstance);
            System.out.println(instance);
            System.out.println(newInstance==instance);

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }  catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

三、懒汉式的反射攻击及解决方法

无法防止反射攻击

public class LazyDoubleCheckSingleton {

	//声明一个需要被单例的对象,初始化时没有被创建所以设置null
    /** volatile修饰的成员变量在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。
     *  而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。
     *  这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
     */
    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton=null;
    
    private static boolean flag =true;
    
    //私有的构造器,不被外部所访问
    private LazyDoubleCheckSingleton(){
    	if(flag){
            flag=false;
        }else{
            throw new RuntimeException("单例构造器进制反射调用");
        }
    }

    //提供一个外部获取LazyDoubleCheckSingleton对象的静态方法
    public  static LazyDoubleCheckSingleton getInstance(){
        if (lazyDoubleCheckSingleton==null){
            synchronized (LazyDoubleCheckSingleton.class){
                if(lazyDoubleCheckSingleton==null){
                    lazyDoubleCheckSingleton=new LazyDoubleCheckSingleton();
                }
            }
        }
        return  lazyDoubleCheckSingleton;
    }
}
public class LazyDoubleCheckTest {
	public static void main(String[] args) {
        try {
            /**
             * @Description: 通过反射获取对象
             * @Author: xz
             * @Date: 2020/5/31 21:06
             */
            //获取class对象
            Class<LazyDoubleCheckSingleton> lazySingletonClass = LazyDoubleCheckSingleton.class;
            //通过获取的class对象,获取声明的构造器
            Constructor<LazyDoubleCheckSingleton> declaredConstructor =  lazySingletonClass.getDeclaredConstructor();
            //去除构造器的私有权限
            declaredConstructor.setAccessible(true);
            
            /**
             * @Description:  直接通过类名.getInstance方法获取对象
             * @Author: xz
             * @Date: 2020/5/31 21:07
             */
            LazyDoubleCheckSingleton instance=LazyDoubleCheckSingleton.getInstance();

            //修改懒汉式的私有属性
            Field  flag = instance.getClass().getDeclaredField("flag");
            flag.setAccessible(true);
            flag.set(instance,true);
            
            //通过构造器创建对象
            LazyDoubleCheckSingleton newInstance = declaredConstructor.newInstance();
            
            //输出2个对象,并判断是否相等
            System.out.println(newInstance);
            System.out.println(instance);
            System.out.println(newInstance==instance);

        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }  catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
}

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值