2015-10-07 76 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的整個想法和現場成員的不變性/可變性:(對不起。錯誤.. :(, –