单例总是可以反射的(反射甚至枚举)
Singleton can always be reflected(Reflection even enum)
我有这个简单的枚举,用作 Object
类型对象的单例提供程序
package package2;
public enum SingletonEnum {
INSTANCE;
private Object obj = new Object();
public Object getObject() {
return obj;
}
}
我有这个反映字段实例的 Sample main,通过分配新对象修改字段
package package2;
import java.lang.reflect.Field;
public class Sample2 {
public static void main(String[] args) {
Object obj = SingletonEnum.INSTANCE.getObject();
System.out.println(obj.hashCode());
try {
Class<?> clazz = Class.forName("package2.SingletonEnum");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType().equals(Object.class)) {
field.setAccessible(true);
field.set(SingletonEnum.INSTANCE, new Object());
}
}
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(SingletonEnum.INSTANCE.getObject().hashCode());
}
}
输出是
1554514352
2112239710
显示了两个不同的哈希码,我假设进行了两次引用。这怎么可能?我以为enum Singletons是唯一的让Singleton "Singleton" 不能被反射的方法,所以这仅仅意味着只有SecurityManager
可以禁止所有反射。所以我的问题是.. "WHAT" 是禁止实例化 Singleton 对象的最安全方法吗?
单例意味着class只能有一个实例。 SingletonEnum
也是如此。这并不意味着实例是不可变的。您正在更改单例的 obj
成员,这会导致不同的哈希码。
在这种情况下,您可以做的是将对象定义为 final,因此它不能更改,但必须对其进行初始化。
public enum SingletonEnum {
INSTANCE;
private final Object obj = new Object();
public Object getObject() {
return obj;
}
}
我有这个简单的枚举,用作 Object
类型对象的单例提供程序
package package2;
public enum SingletonEnum {
INSTANCE;
private Object obj = new Object();
public Object getObject() {
return obj;
}
}
我有这个反映字段实例的 Sample main,通过分配新对象修改字段
package package2;
import java.lang.reflect.Field;
public class Sample2 {
public static void main(String[] args) {
Object obj = SingletonEnum.INSTANCE.getObject();
System.out.println(obj.hashCode());
try {
Class<?> clazz = Class.forName("package2.SingletonEnum");
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
if (field.getType().equals(Object.class)) {
field.setAccessible(true);
field.set(SingletonEnum.INSTANCE, new Object());
}
}
}
catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println(SingletonEnum.INSTANCE.getObject().hashCode());
}
}
输出是
1554514352
2112239710
显示了两个不同的哈希码,我假设进行了两次引用。这怎么可能?我以为enum Singletons是唯一的让Singleton "Singleton" 不能被反射的方法,所以这仅仅意味着只有SecurityManager
可以禁止所有反射。所以我的问题是.. "WHAT" 是禁止实例化 Singleton 对象的最安全方法吗?
单例意味着class只能有一个实例。 SingletonEnum
也是如此。这并不意味着实例是不可变的。您正在更改单例的 obj
成员,这会导致不同的哈希码。
在这种情况下,您可以做的是将对象定义为 final,因此它不能更改,但必须对其进行初始化。
public enum SingletonEnum {
INSTANCE;
private final Object obj = new Object();
public Object getObject() {
return obj;
}
}