• 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的构造函数,而是直接生成了两个实例。

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

  • 相关阅读:
    动手学习TCP:TCP连接建立与终止
    动手学习TCP: 环境搭建
    Python 数据分析4
    Django unittest 单元测试
    Django commands自定制
    Python mac安装mysqlclient的一个bug
    Centos7 开机启动流程
    Centos 06 文件类型和扩展名&索引节点inode和存储块block
    Centos 05 系统目录讲解
    Linux 踩过的坑系列-01
  • 原文地址:https://www.cnblogs.com/kuillldan/p/7460314.html
Copyright © 2020-2023  润新知