2011-09-30 87 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 - 因为它都发生在枚举类的静态初始化中,所以它本质上是线程安全的。 –