zoukankan      html  css  js  c++  java
  • Java中反射和Unsafe破坏单例设计模式

    有如下单例模式设计代码:

    class Singleton
    {
        private String info = "HELLO SHIT";
    
        private static Singleton instance;
    
        private Singleton()
        {
            System.out.println("******实例化对象******");
        }
    
        public static Singleton getInstance()
        {
            synchronized (Singleton.class)
            {
                if (instance == null)
                {
                    instance = new Singleton();
                }
            }
            return instance;
        }
    
        public void show()
        {
            System.out.println("www.google.com");
        }
    }

    按照规则,我们只能获取一个实例化的对象,如下面的代码:

    public class Hello
    {
        public static void main(String[] args) throws Exception
        {
            Singleton instanceA = Singleton.getInstance();
            Singleton instanceB = Singleton.getInstance();
            System.out.println(instanceA.hashCode());
            System.out.println(instanceB.hashCode());
            System.out.println(instanceA == instanceB);
        }
    }

    程序输出:

    ******实例化对象******
    685325104
    685325104
    true
    
    Process finished with exit code 0

    可以看到instanceA和instanceB完全相同.

    下面演示用反射获取单例的构造函数,并且实例化出多个对象:

    public class Hello
    {
        public static void main(String[] args) throws Exception
        {
            Constructor c = Singleton.class.getDeclaredConstructor();
            c.setAccessible(true);
    
            Singleton instanceA = (Singleton)c.newInstance();
            Singleton instanceB = (Singleton)c.newInstance();
            System.out.println(instanceA.hashCode());
            System.out.println(instanceB.hashCode());
            System.out.println(instanceA == instanceB);
        }
    }

    程序输出:

    ******实例化对象******
    ******实例化对象******
    685325104
    460141958
    false
    
    Process finished with exit code 0

    可以看到,这里调用了两次构造函数,实例化了两个不同的Singleton对象。

    除了用反射,我们还可以用Unsafe类实例化多个单例对象,这种方式和反射的区别在于:Unsafe不需要调用构造函数。因为Unsafe是使用C++进行JVM底层控制。代码如下:

    public class Hello
    {
        public static void main(String[] args) throws Exception
        {
            Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
            theUnsafeField.setAccessible(true);
            Unsafe unsafeInstance = (Unsafe)theUnsafeField.get(null);
            Singleton instanceA = (Singleton)unsafeInstance.allocateInstance(Singleton.class);
            Singleton instanceB = (Singleton)unsafeInstance.allocateInstance(Singleton.class);
            System.out.println(instanceA.hashCode());
            System.out.println(instanceB.hashCode());
            System.out.println(instanceA == instanceB);
        }
    }

    程序输出:

    460141958
    1163157884
    false
    
    Process finished with exit code 0

    可以发现上面的代码根本没有调用Singleton的构造函数,而是直接生成了两个实例。

    其实上面的代码并没有太大意义,只是作为知识点可以加深对反射和单例的理解和印象。

  • 相关阅读:
    3、Spring Cloud Rest工程创建(通过IDEA创建)
    Centos7配置阿里epel源|yum源
    OSI七层模型:TCP/IP && HTTP && WebSocket && MQTT
    几种进程间的通信方式
    Tomcat类加载机制
    JAVA类加载器
    Spring事务隔离级别
    Spring事务传播特性
    Spring事务实现原理
    RPC框架Dubbo分析
  • 原文地址:https://www.cnblogs.com/kuillldan/p/7460314.html
Copyright © 2011-2022 走看看