2011-09-30 82 views
0

考慮下面的代碼,Java 1.5 Enum:爲什麼我不能在1.5枚枚舉中使用'findBy'?

import java.util.Date; 
import java.util.HashMap; 
import java.util.Map; 

public enum SearchDataTypes { 

    FIELD_DATATYPE_TEXT(String.class,"_t"), 
    FIELD_DATATYPE_INT(Integer.class,"_i"), 
    FIELD_DATATYPE_LONG(Long.class,"_l"), 
    FIELD_DATATYPE_FLOAT(Float.class,"_f"), 
    FIELD_DATATYPE_DOUBLE(Double.class, "_d"), 
    FIELD_DATATYPE_DATE(Date.class,"_dt"); 

    SearchDataTypes(final Class<?> clazz, final String affix) { 
    this.affix = affix; 
    this.clazz = clazz; 
    getAffixMap().put(affix, this); 
    getClassMap().put(clazz, this); 
    } 

    public String getFieldName(String objectFieldName) { 
    return objectFieldName+affix; 
    } 

    public String getObjectFieldName(String FieldName) { 
    int len = FieldName.length(); 
    len -= this.affix.length(); 
    return FieldName.substring(0, len); 
    } 
    public static SearchDataTypes findByAffix(String affix) { 
    SearchDataTypes obj = getAffixMap().get(affix); 
    assert obj != null; 
    return obj; 
    } 

    public static SearchDataTypes findByClass(Class<?> clazz) { 
    SearchDataTypes obj = getClassMap().get(clazz); 
    assert obj != null; 
    return obj; 
    } 

    private String affix; 
    private Class<?> clazz; 

    private static Map<Class<?>, SearchDataTypes> classMap = new HashMap<Class<?>, SearchDataTypes>(); 
    private static Map<String, SearchDataTypes> affixMap = new HashMap<String, SearchDataTypes>(); 

    private static Map<Class<?>, SearchDataTypes> getClassMap() { return classMap; } 
    private static Map<String, SearchDataTypes> getAffixMap() { return affixMap; } 


} 

枚舉類是沒有得到實例化(使用枚舉拋出NoClassDefFoundError的),因爲有初始化期間NullPointerException異常。我假設JVM認爲map是null。但爲什麼??

我還可以爲枚舉實現取景器嗎?我更喜歡不使用java.util.EnumMap類,主要是因爲我想更好地理解枚舉的內部工作。

謝謝

+0

什麼是NPE的實際回溯?你需要調試它。 – bmargulies

+0

如果我能看到NPE,我不會發表這個。 NPE沒有被JVM打印。 – jabawaba

+0

我不認爲枚舉支持靜態地圖字段。但是,我必須要做一個替代方案。 – jabawaba

回答

4

將枚舉常量看作Java類的公共靜態最終成員。像所有靜態成員一樣,它們按源代碼順序初始化。所以常量在映射之前被初始化,因此在引用構造函數中的映射時你會得到空指針異常,因爲映射還沒有被初始化。

儘管java語法不可能,但簡單的解決方案是在枚舉之前聲明映射 - 但由於這是不可能的,所以最好的辦法是在常量之後初始化靜態塊中的映射。

public enum SearchDataTypes { 
    ... 
    FIELD_DATATYPE_DATE(Date.class,"_dt"); 

    private static final Map<String,SearchDataTypes> affixMap = new HashMap<String,SearchDataType>(); 
    private static final Map<Class<?>, SearchDataTypes> classMap = new HashMap<Class<?>, SearchDataTypes>() 
    static { 
     for (SearchDataType value : values()) { 
      map.put(value.affix, value); 
      map.put(value.clazz, value); 
     } 
    } 

    SearchDataTypes(final Class<?> clazz, final String affix) { 
     this.affix = affix; 
    ... 
} 
+0

我發現自己經常這樣做,所以我建立了一個通用的幫助類和註釋來爲我做這件事:http://riversoforion.git.sourceforge.net/git/gitweb.cgi?p=riversoforion/riversoforion;a=blob ; F =黃泉/中繼/ java的utils的/ SRC /主/ JAVA/COM/riversoforion /黃泉/枚舉/ AlternateValueHelper.java – Mac

2

實例在靜態初始化其餘枚舉之前構造。使用「getters」作爲構造它們的地圖,如果它們爲null的話。

因爲它都發生在枚舉類的靜態初始化中,所以它本質上是線程安全的 - 您不必使用同步塊。

+0

這是一個很好的解決方案,我曾嘗試過。我遇到的一個障礙是將映射的實例化(如果爲空)包裝在同步塊中。但是,我沒有「通用」對象監視器進行同步。我意識到兩個線程同時觸發getter的概率很小,但我總是更喜歡我的類是線程安全的。 – jabawaba

+0

@jabawaba - 因爲它都發生在枚舉類的靜態初始化中,所以它本質上是線程安全的。 –