2010-11-25 4 views
2

В этом коде я получаю ошибку компилятора, смотрите комментарии:не удается получить доступ к статическому полю в перечислении инициализатора

public enum Type { 
    CHANGESET("changeset"), 
    NEW_TICKET("newticket"), 
    TICKET_CHANGED("editedticket"), 
    CLOSED_TICKET("closedticket"); 

    private static final Map<String, Type> tracNameMap = new HashMap<String, Type>(); 

    private Type(String name) { 
    tracNameMap.put(name, this); // cannot refer to static field within an initializer 
    } 

    public static Type getByTracName(String tn) { 
    return tracNameMap.get(tracNameMap); 
    } 

    } 

Есть ли способ, чтобы сделать эту работу, получить значение перечисления из Map одним из его полей ?

+0

Возможно, стоит указать, является ли «ключ» для карты всегда «именем» перечисления. Если это так, это имеет большое значение в том, как вы это сделаете. – DJClayworth 2010-11-25 16:53:05

ответ

9

Карта вероятно, слишком много здесь. Если вы планируете иметь более четырех значений enum, вы можете реализовать getByTracName (String tn), просто перейдя по допустимым строкам и вернув правильный. Если ключи карта всегда имена перечислений, то вы можете сделать:

public enum Type { 
CHANGESET, 
NEW_TICKET, 
TICKET_CHANGED, 
CLOSED_TICKET; 

private static final Map<String, Type> tracNameMap = new HashMap<String, Type>(); 
static { 
    for (Type t:Type.values()) { 
     tracNameMap.put(t.name(), t); 
    } 
} 
public static Type getByTracName(String tn) { 
    return tracNameMap.get(tracNameMap); 
} 

}

или вы можете сделать:

public static Type getByTracName(String tn) { 
    return Enum.valueOf(Type.class,tn); 
} 
+1

`Enum. valueOf (Type.class, tn) `должно быть записано как` Type.valueOftn) ` – user102008 2010-12-30 10:00:28

0

свой обходной путь, хотя он требует повторения всех значений перечислений:

public enum Type { 
     CHANGESET, 
     NEW_TICKET, 
     TICKET_CHANGED, 
     CLOSED_TICKET; 

     private static final Map<String, Type> tracNameMap = new HashMap<String, Type>(); 
     static { 
      tracNameMap.put("changeset", CHANGESET); 
      tracNameMap.put("newticket", NEW_TICKET); 
      tracNameMap.put("editedticket", TICKET_CHANGED); 
      tracNameMap.put("closedticket", CLOSED_TICKET); 
     } 
     public static Type getByTracName(String tn) { 
      return tracNameMap.get(tracNameMap); 
     } 

    } 
+0

Добавив немного больше кода, вы можете уменьшить повторение кода, как указано здесь: http://stackoverflow.com/questions/4278432/cannot-access-static-field-within-enum-initialiser/4278931#4278931 – 2010-11-25 16:11:15

2

Я бы использовать Reversible Enum Pattern:

ReversibleEnum .java

/** 
* <p> 
* This interface defines the method that the {@link Enum} implementations 
* should implement if they want to have the reversible lookup functionality. 
* i.e. allow the lookup using the code for the {@link Enum} constants. 
* </p> 
* @author Atif Khan 
* @param <E> 
*   The value of Enum constant 
* @param <V> 
*   The Enum constant to return from lookup 
*/ 
public interface ReversibleEnum< E, V > 
{ 
    /** 
    * <p> 
    * Return the value/code of the enum constant. 
    * </p> 
    * @return value 
    */ 
    public E getValue(); 

    /** 
    * <p> 
    * Get the {@link Enum} constant by looking up the code in the reverse enum 
    * map. 
    * </p> 
    * @param E - code 
    * @return V - The enum constant 
    */ 
    public V reverse(E code); 
} 

ReverseEnumMap.java

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

/** 
* <p> 
* A utility class that provides a reverse map of the {@link Enum} that is keyed 
* by the value of the {@link Enum} constant. 
* </p> 
* @author Atif Khan 
* @param <K> 
*   The class type of the value of the enum constant 
* @param <V> 
*   The Enum for which the map is being created 
*/ 
public class ReverseEnumMap< K, V extends ReversibleEnum< K, V >> 
{ 
    private final Map< K, V > mReverseMap = new HashMap< K, V >(); 

    /** 
    * <p> 
    * Create a new instance of ReverseEnumMap. 
    * </p> 
    * @param valueType 
    */ 
    public ReverseEnumMap(final Class<V> valueType) 
    { 
    for(final V v : valueType.getEnumConstants()) { 
     mReverseMap.put(v.getValue(), v); 
    } 
    } 

    /** 
    * <p> 
    * Perform the reverse lookup for the given enum value and return the enum 
    * constant. 
    * </p> 
    * @param enumValue 
    * @return enum constant 
    */ 
    public V get(final K enumValue) 
    { 
    return mReverseMap.get(enumValue); 
    } 
} 

Вы бы изменить Type.java следующим образом:

public enum Type implements ReversibleEnum< String, Type > { 
    CHANGESET("changeset"), 
    NEW_TICKET("new"), 
    TICKET_CHANGED("changed"), 
    CLOSED_TICKET("closed"); 

    private String mValue; 

    private static final ReverseEnumMap< String, Type > mReverseMap = new ReverseEnumMap< String, Type >(Type.class); 

    Type(final String value) 
    { 
    mValue = value; 
    } 

    public final String getValue() 
    { 
    return mValue; 
    } 

    public Type reverse(final String value) 
    { 
    return mReverseMap.get(value); 
    } 
} 
+0

Немного переработано, я должен сказать. :-) – 2010-11-25 16:09:48

1

Как об этом; не требует, чтобы вы вносили изменения кода в двух местах, которые являются своего рода погрешностью. IMO:

enum Type { 

    CHANGESET("changeset"), 
    NEW_TICKET("newticket"), 
    TICKET_CHANGED("editedticket"), 
    CLOSED_TICKET("closedticket"); 

    private static final Map<String, Type> tracNameMap = 
             new HashMap<String, Type>(); 

    private final String name; 

    public Type typeForName(final String name) { 
     if (tracNameMap.containsKey(name)) { 
      return tracNameMap.get(name); 
     } else { 
      for (final Type t : Type.values()) { 
       if (t.name.equals(name)) { 
        tracNameMap.put(name, t); 
        return t; 
       } 
      } 
      throw new IllegalArgumentException("Invalid enum name"); 
     } 
    } 

    private Type(String name) { 
     this.name = name; 
    } 

} 
7

Hah, funny! Всего несколько дней назад я наткнулся на это.

Из спецификации языка Java, Третье издание, Раздел 8.9:

Это ошибка времени компиляции для ссылки на статическое поле типа перечислений, который не является константой времени компиляции (§15.28) от конструкторов, блоков инициализатора экземпляра или выражений инициализатора экземпляра этого типа. Это ошибка времени компиляции для конструкторов, блоков инициализатора экземпляра или выражений инициализатора экземпляра константы enum e для ссылки на себя или на константу перечисления того же типа, которая объявляется справа от e.

Обсуждение

Без этого правила, по-видимому, разумно код потерпит неудачу во время выполнения из-за инициализацию округлость, присущие типов перечислений. (А округлость существует в любом классе с «самостоятельной напечатал» статического поля.) Вот пример подобного кода, который будет терпеть неудачу:

enum Color { 
     RED, GREEN, BLUE; 
     static final Map<String,Color> colorMap = 
     new HashMap<String,Color>(); 
     Color() { 
      colorMap.put(toString(), this); 
     } 
    } 

Статическая инициализация этого перечислимого типа будет бросать NullPointerException, потому что статическая переменная colorMap не инициализируется, когда выполняются конструкторы для констант перечисления. Ограничение выше гарантирует, что такой код не будет компилироваться.

Обратите внимание, что пример может быть легко переработан, чтобы работать должным образом:

enum Color { 
     RED, GREEN, BLUE; 
     static final Map<String,Color> colorMap = 
     new HashMap<String,Color>(); 
     static { 
      for (Color c : Color.values()) 
       colorMap.put(c.toString(), c); 
     } 
    } 

переработан версия явно правильно, так как статическая инициализация происходит сверху вниз.