zoukankan      html  css  js  c++  java
  • 反射如何破坏单例模式

    一个单例类:

    
    
    public class Singleton {
        private static Singleton instance = new Singleton();   
    
        private Singleton() {} 
    
        public static Singleton getInstance() {
            return instance;
        }
    }
     

    通过反射破坏单例模式:

    
    
    public class Test {
        public static void main(String[] args) throws Exception{
            Singleton s1 = Singleton.getInstance();
    
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton s2 = constructor.newInstance();
    
            System.out.println(s1.hashCode());
            System.out.println(s2.hashCode());
    
        }
    }
    
    
    

      

    输出结果:
    671631440

    935563443

    结果表明s1和s2是两个不同的实例了。

    通过反射获得单例类的构造函数,由于该构造函数是private的,通过setAccessible(true)指示反射的对象在使用时应该取消 Java 语言访问检查,使得私有的构造函数能够被访问,这样使得单例模式失效。

     

    如果要抵御这种攻击,要防止构造函数被成功调用两次。需要在构造函数中对实例化次数进行统计,大于一次就抛出异常。

    
    
    public class Singleton {
        private static int count = 0;
    
        private static Singleton instance = null; 
    
        private Singleton(){
            synchronized (Singleton.class) {
                if(count > 0){
                    throw new RuntimeException("创建了两个实例");
                }
                count++;
            }
    
        }
    
        public static Singleton getInstance() {
            if(instance == null) {
                instance = new Singleton();
            }
            return instance;
        }
    
        public static void main(String[] args) throws Exception {
    
            Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            Singleton s1 = constructor.newInstance();
            Singleton s2 = constructor.newInstance();
        }
    
    }
    
    执行结果:
    Exception in thread "main" java.lang.reflect.InvocationTargetException
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at com.yzz.reflect.Singleton.main(Singleton.java:33)
    Caused by: java.lang.RuntimeException: 创建了两个实例
        at com.yzz.reflect.Singleton.<init>(Singleton.java:14)
        ... 5 more
    
    
    
    在通过反射创建第二个实例时抛出异常,防止实例化多个对象。构造函数中的synchronized是为了防止多线程情况下实例化多个对象。
  • 相关阅读:
    iOS 添加微信分享
    IOS学习笔记——ViewController生命周期详解
    UI之CALayer详解(转)
    iOS CALayer讲解
    [leetcode] Minimum Path Sum
    [leetcode]Binary Tree Maximum Path Sum
    我是真的想去google啊
    C++ string 用法详解
    继续存博客
    bash中 2>&1 & 的解释
  • 原文地址:https://www.cnblogs.com/wyb628/p/6371827.html
Copyright © 2011-2022 走看看