2015-10-07 71 views
0

我有这个简单枚举充当一个Singleton提供商为Object类型的对象辛格尔顿总是可以反映(反射甚至枚举)

package package2; 

public enum SingletonEnum { 

    INSTANCE; 
    private Object obj = new Object(); 

    public Object getObject() { 
     return obj; 
    } 
} 

,我有这个样品主要反映现场情况,修改通过分配新对象字段

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 

显示两个不同的哈希码,我假设有两个引用。这怎么可能?我认为枚举Singletons是使Singleton“Singleton”不能被反射的唯一方法,所以这只意味着只有SecurityManager可以禁止所有的反射。所以我的问题是......“什么”是禁止一个Singleton对象实例化的最安全的方法?

+0

目前还不清楚你在问什么。 'SingletonEnum.INSTANCE' *是*单身人士。这并不意味着它是不可变的。此外,当你修改单例的字段时,其他对象的实例化不会发生,当你执行'new Object()'时,它已经发生了。 – Holger

回答

0

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

public enum SingletonEnum { 

    INSTANCE; 
    private final Object obj = new Object(); 

    public Object getObject() { 
     return obj; 
    } 
} 
+0

由于OP使用'.setAccessible(true)',所以声明'final'字段没有帮助。 – Holger

+0

对不起,谢谢你,我一直沉迷于Java反射和Singleton的完全安全..我没有注意到我开始忘记Singleton的整个想法和现场成员的不变性/可变性:(对不起。错误.. :(, –