这里的加了枚举的单例模式是否有问题
来源:5-6 无视反射和序列化攻击的单例
慕数据4154996
2020-03-26
先给出老师的饿汉式枚举封装的单例代码。
public class EnumStarvingSingleton {
private EnumStarvingSingleton(){}
public static EnumStarvingSingleton getInstance(){
return ContainerHolder.HOLDER.instance;
}
private enum ContainerHolder{
HOLDER;
private EnumStarvingSingleton instance;
ContainerHolder(){
instance = new EnumStarvingSingleton();
}
}
}
再给出我的测试用例:
public class SingletonDemo {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor constructor = EnumStarvingSingleton.class.getDeclaredConstructor();
constructor.setAccessible(true);
EnumStarvingSingleton instance1 = (EnumStarvingSingleton) constructor.newInstance();
EnumStarvingSingleton instance2 = EnumStarvingSingleton.getInstance();
System.out.println(instance1 == instance2);
}
}
我的测试用例结果是false,说明反射已经破坏了该单例模式。
一般用枚举类型抵御反射对单例的破坏,直接用枚举就行了,如下述代码所示:
public enum Singleton {
INSTANCE
}
测试代码如下:
public class SingletonDemo {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Constructor constructor = Singleton.class.getDeclaredConstructor(String.class, int.class);
constructor.setAccessible(true);
Singleton instance1 = (Singleton) constructor.newInstance();
Singleton instance2 = Singleton.INSTANCE;
System.out.println(instance1 == instance2);
}
}
上述测试会抛出IllegalArgumentException异常,因为枚举类无法通过反射来创建实例。
不知道为什么老师这里要多一层封装,把枚举作为私有的内部类来处理?
写回答
1回答
-
同学好,你的这个变量名字好有迷惑性呀。。
Constructor constructor = EnumStarvingSingleton.class.getDeclaredConstructor(); EnumStarvingSingleton instance1 = (EnumStarvingSingleton) constructor.newInstance();
这个是EnumStarvingSingleton实例本身吧。。
EnumStarvingSingleton instance2 = EnumStarvingSingleton.getInstance();
EnumStarvingSingleton instance2 = EnumStarvingSingleton.getInstance(); 这个才是枚举的实例呢。。所以针对枚举的实例来讲,是单例的呀。
这里用内部枚举的原因主要就是通过内部枚举持有容器单例。保证持有的容器单例是不会被破坏的。。
052020-03-28
相似问题