单例模式如何防范反射机制

Pack 发布于 2019-12-26 15:39
阅读 279
收藏 0
分类:设计模式

看单例模式视频时,发现老师通过在构造方法里面增加判断的方式防止被反射,但是实际测试代码中,发现如果先反射,然后再用getInstance方法,获取的对象不是同一个,请大神帮忙看看,谢谢~

public class DoubleCheckLazySingleton {

    private DoubleCheckLazySingleton() throws Exception {

        if (instance != null) {

            throw new Exception("单例不允许被反射");

        }

    }


    private static DoubleCheckLazySingleton instance;


    public static DoubleCheckLazySingleton getInstance() throws Exception {

        if (instance == null) {

            synchronized (DoubleCheckLazySingleton.class) {

                if (instance == null) {

                    instance = new DoubleCheckLazySingleton();

                }

            }

        }


        return instance;

    }

}

测试方法

public class DestroySingleByReflect {

    public static void main(String[] args) throws Exception {

        DoubleCheckLazySingleton oinstance = null;

DoubleCheckLazySingleton oinstance2 = null;

        DoubleCheckLazySingleton oinstance3 = null;

        Class clazz = DoubleCheckLazySingleton.class;

        try {

            Constructor c = clazz.getDeclaredConstructor();

            c.setAccessible(true);

            oinstance = (DoubleCheckLazySingleton) c.newInstance();

    oinstance2 = (DoubleCheckLazySingleton) c.newInstance();

            oinstance3 = (DoubleCheckLazySingleton) c.newInstance();

        } catch (Exception e) {

            e.printStackTrace();

        }

        DoubleCheckLazySingleton instance = DoubleCheckLazySingleton.getInstance();

        System.out.println(oinstance);

System.out.println(oinstance2);

System.out.println(oinstance3);

        System.out.println(instance);

    }

}

测试结果

com.xx.singleton.lazy.DoubleCheckLazySingleton@1b6d3586

com.xx.singleton.lazy.DoubleCheckLazySingleton@4554617c

com.xx.singleton.lazy.DoubleCheckLazySingleton@74a14482

com.xx.singleton.lazy.DoubleCheckLazySingleton@1540e19d

33
Pack
Pack

从调式的角度来看,当从反射的入口进来时,instance当时的值为null,直接执行成功,创建好实例对象,可此时并未将此实例对象赋值给类中的instance变量,而只是在jvm中存在该实例对象。而通过getInstance的方式进来后,该类下的变量的值的确还是为null。所以最终返回两个内存地址是正确的。

这个跟类加载和jvm内存模型有关,目前理解不深。只能简单聊下,虽然变量通过static 修饰,但也只是提前在jvm中分配一个地址放变量,而通过默认构造器也只是实例个对象,两者之间并没有引用关系。所以单例中的双重校验也无法正确校验。

请先 登录 后评论