单例总是可以被反射的(反射甚至是枚举)



我有这个简单的enum作为Object类型对象的Singleton提供者

package package2;
public enum SingletonEnum {
    INSTANCE;
    private Object obj = new Object();
    public Object getObject() {
        return obj;
    }
}

并且我有这个反映字段实例的示例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 Singleton是使Singleton成为"Singleton"而不能反射的唯一方法,所以这只意味着只有SecurityManager可以禁止所有反射。我的问题是…"什么"是禁止单例对象实例化的最安全的方法?

单例意味着该类只能有一个实例。这对SingletonEnum是正确的。这并不意味着实例是不可变的。您正在更改单例的obj成员,这会导致不同的哈希码。在这种情况下,您可以做的是定义对象final,因此它不能被更改,尽管它必须初始化。

public enum SingletonEnum {
    INSTANCE;
    private final Object obj = new Object();
    public Object getObject() {
        return obj;
    }
}

相关内容

  • 没有找到相关文章

最新更新