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的一个字段中获取一个枚举值?

4

5 回答 5

9

这里的地图可能有点矫枉过正。除非您计划拥有四个以上的枚举值,否则您可以通过简单地遍历有效字符串并返回正确的字符串来实现 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);
}
于 2010-11-25T15:20:41.193 回答
7

哈哈,好笑!就在几天前,我偶然发现了这个。

来自 Java 语言规范,第三版,第 8.9 节:

从构造函数、实例初始化程序块或该类型的实例变量初始化程序表达式引用不是编译时常量(第 15.28 节)的枚举类型的静态字段是编译时错误。枚举常量 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);
        }
    } 

重构后的版本显然是正确的,因为静态初始化从上到下发生。

于 2010-12-12T00:26:53.007 回答
2

我会使用可逆枚举模式

可逆枚举.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 );  
  } 
} 
于 2010-11-25T15:55:32.130 回答
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;
    }

}
于 2010-11-25T16:08:53.143 回答
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);
        }

    }
于 2010-11-25T15:08:52.953 回答