【Java】反射与单例

来源:互联网 发布:c 结构体数组 编辑:程序博客网 时间:2024/06/05 02:11

双重检验与静态内部类两种方法都可以实现延迟加载的单例模式。但是无法阻止反射破坏单例,因为反射可以无视修饰权限,直接调用构造方法创建对象,下面是一个例子:

package ThreadTest;public class Singleton {private Singleton(){}       static class SingletonGen{private static final Singleton instance = new Singleton();}public static Singleton getInstance(){return SingletonGen.instance;}public static void main(String args[]){Singleton s = Singleton.getInstance();try {Class clazz = Class.forName("ThreadTest.Singleton");Singleton sss = (Singleton) clazz.newInstance();System.out.println(s.hashCode());System.out.println(sss.hashCode());} catch (ClassNotFoundException e) {e.printStackTrace();} catch (InstantiationException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();}}}
最终两个对象的hashcode不同,说明是两个对象。

那么如何解决反射破坏呢?可以类内创建一个标志变量,在构造方法内部检测该标志变量,使得构造方法只执行一次。但是这个检测必须 是线程安全的,必须同步,那么是类锁还是对象锁?很显然是类锁,因为多线程中的反射是以类为单位进行的,所以需要类锁。

private static boolean flag = false;private Singleton(){synchronized (Singleton.class) {if(!flag){flag = true;}else{throw new RuntimeException("单例被破坏");}}}

这样,不论以什么方式,只要是通过构造方法来破坏单例,都会被阻止。