Given the code below,
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; }
}
The enum class is not getting instantiated (using the enum throws NoClassDefFoundError) because the there is NullPointerException during initialization. I assume that the JVM is thinking either map is null. But why??
How else can I implement a finder for enums? I prefer not to use java.util.EnumMap class main开发者_如何学Goly because I want to better understand the innerworking of enums.
thank you
Think of the enum constants as public static final members of the Java class. Like all static members, they are initialized in source order. So the constants are being initialized before the maps, thus you'll get the null pointer exception when referencing the map in the constructors, because the map hasn't been initialized yet.
Though not possible with java syntax, the simple solution would be to declare the maps before the enums--but since that's not possible, the next best thing is to just initialize the maps in a static block after the constants: e.g.
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;
...
}
The instances are getting constructed before the static initialization of the rest of the enum. Use "getters" for the maps that will construct them if they are null.
Because it's all happening within static initialization of the enum class, it's intrinsically thread-safe - you don't have to use a synchronize block.
精彩评论