我们都知道单例模式是为了实现只创建一个实例,但是java 的反射机制可以破坏这种单例模式,这种通过反射来破坏单例的例子网上多的是,我就不列出来了,今天我们来说说怎么防止使用java的反射机制来破坏单例,查了查网上有很多是在单例的类中增加一个boolean类型的flag,然后在构造函数中来改变flag的值,然后再调用构造函数的时候判断这个flag是否已经改变了,这样来防止重复创建对象实例,当看到这种解决办法的时候就觉得这种方法是不严谨的,因为既然可以通过反射来获取构造函数来创建实例了,那么同样可以通过反射来获取到你定义的flag,那么在利用反射调用构造函数之前,先获取到你这个flag,然后将值重置,那么再次调用构造函数就不会受到限制了,那这样实际上就没有起到防止重复创建的效果。于是我使用了自己想出来的如下方法:
public class SingletonClass {
// private static final Boolean flag = Boolean.FALSE;
private static ImmutableBoolean flag = new ImmutableBoolean();
private SingletonClass() {
if (flag.getCount() <= 0) {
synchronized (SingletonClass.class) {
if (flag.getCount() <= 0) {
flag.setCount();
} else {
throw new RuntimeException("正在破坏单例模式1");
}
}
} else {
throw new RuntimeException("正在破坏单例模式2");
}
}
private static SingletonClass singletonClass = null;
public static SingletonClass getInstance() {
if (singletonClass == null) {
synchronized (SingletonClass.class) {
if (singletonClass == null) {
singletonClass = new SingletonClass();
}
}
}
return singletonClass;
}
private static class ImmutableBoolean {
private static int count = 0;
public ImmutableBoolean() {
}
public void setCount() {
synchronized (SingletonClass.class) {
if (count <= 0) {
count ++;
} else {
throw new RuntimeException("");
}
}
}
public int getCount(){
return count;
}
}
}
public class TestClass {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
SingletonClass s1 = SingletonClass.getInstance();
// System.out.println(s1);
Classc1 = SingletonClass.class;
// s1.new ImmutableBoolean();
// SingletonClass.ImmutableBoolean
// Field[] fields = c1.getDeclaredFields();
// for (Field field : fields) {
// System.out.println(field.getName());
// if ("flag".equals(field.getName())) {
// field.setAccessible(true);
// Class c2 = field.getClass();
// System.out.println(c2.getName());
Class c3 = field.
System.out.println(c3.getName());
field.
field.setBoolean(s1, false);
break;
// }
// }
Constructorconstructor = c1.getDeclaredConstructor();
constructor.setAccessible(true);
SingletonClass s2 = constructor.newInstance();
System.out.println(s1 == s2);
}
}
我定义了一个私有的内部类,然后用这个内部类的属性来作为flag,这样外面的其他类就获取不到这个私有的内部类,也就不能改变它的值了,从而保护了单例的实现。