从枚举序号转换为枚举类型

时间:2009-03-04 09:32:07

标签: java enums

我的枚举类型ReportTypeEnum在所有类中的方法之间传递,但我需要在URL上传递它,所以我使用序数方法来获取int值。在我的其他JSP页面中获取它之后,我需要将其转换回ReportTypeEnum以便我可以继续传递它。

如何将序数转换为ReportTypeEnum

使用Java 6 SE。

12 个答案:

答案 0 :(得分:575)

要将序数转换为enum represantation,您可能需要执行此操作:

ReportTypeEnum value = ReportTypeEnum.values()[ordinal];

请注意数组边界。

请注意,每次调用values()都会返回一个新克隆的数组,这可能会以负面的方式影响性能。如果要经常调用它,您可能希望缓存该数组。

Code example on how to cache values()


编辑了这个答案,以包括评论中给出的反馈

答案 1 :(得分:136)

这几乎肯定是一个坏主意。当然,如果序数 de-facto 持久存在(例如因为有人为URL添加了书签) - 这意味着您将来必须始终保留enum顺序,这对代码来说可能并不明显维护人员。

为什么不使用enum(并通过myEnumValue.name()解码)对ReportTypeEnum.valueOf(s)进行编码?

答案 2 :(得分:87)

如果我要经常使用values()

enum Suit {
   Hearts, Diamonds, Spades, Clubs;
   public static final Suit values[] = values();
}

同时wherever.java:

Suit suit = Suit.values[ordinal];

注意阵列界限。

答案 3 :(得分:7)

可以使用静态查找表:

public enum Suit {
  spades, hearts, diamonds, clubs;

  private static final Map<Integer, Suit> lookup = new HashMap<Integer, Suit>();

  static{
    int ordinal = 0;
    for (Suit suit : EnumSet.allOf(Suit.class)) {
      lookup.put(ordinal, suit);
      ordinal+= 1;
    }
  }

  public Suit fromOrdinal(int ordinal) {
    return lookup.get(ordinal);
  }
}

答案 4 :(得分:7)

我同意大多数人使用序数可能是一个坏主意。我通常通过给枚举一个私有构造函数来解决这个问题,该构造函数可以采用例如DB值,然后创建一个类似于Jan答案中的静态fromDbValue函数。

public ReportTypeEnum {
    R1(1),
    R2(2),
    R3(3),
    R4(4),
    R5(5),
    R6(6),
    R7(7),
    R8(8);

    private static Logger log = LoggerFactory.getLogger(ReportEnumType.class);  
    private static Map<Integer, ReportTypeEnum> lookup;
    private Integer dbValue;

    private ReportTypeEnum(Integer dbValue) {
        this.dbValue = dbValue;
    }


    static {
        try {
            ReportTypeEnum[] vals = ReportTypeEnum.values();
            lookup = new HashMap<Integer, ReportTypeEnum>(vals.length);

            for (ReportTypeEnum  rpt: vals)
                lookup.put(rpt.getDbValue(), rpt);
         }
         catch (Exception e) {
             // Careful, if any exception is thrown out of a static block, the class
             // won't be initialized
             log.error("Unexpected exception initializing " + ReportTypeEnum.class, e);
         }
    }

    public static ReportTypeEnum fromDbValue(Integer dbValue) {
        return lookup.get(dbValue);
    }

    public Integer getDbValue() {
        return this.dbValue;
    }

}

现在您可以在不更改查找的情况下更改顺序,反之亦然。

答案 5 :(得分:4)

这就是我使用的。我并没有假装它比上面简单的解决方案更“有效”。当在上面的解决方案中使用无效的序数值时,它所做的是提供比“ArrayIndexOutOfBounds”更清晰的异常消息。

它利用了EnumSet javadoc指定迭代器以其自然顺序返回元素的事实。如果这不正确,就会有一个断言。

JUnit4测试演示了它是如何使用的。

 /**
 * convert ordinal to Enum
 * @param clzz may not be null
 * @param ordinal
 * @return e with e.ordinal( ) == ordinal
 * @throws IllegalArgumentException if ordinal out of range
 */
public static <E extends Enum<E> > E lookupEnum(Class<E> clzz, int ordinal) {
    EnumSet<E> set = EnumSet.allOf(clzz);
    if (ordinal < set.size()) {
        Iterator<E> iter = set.iterator();
        for (int i = 0; i < ordinal; i++) {
            iter.next();
        }
        E rval = iter.next();
        assert(rval.ordinal() == ordinal);
        return rval;
    }
    throw new IllegalArgumentException("Invalid value " + ordinal + " for " + clzz.getName( ) + ", must be < " + set.size());
}

@Test
public void lookupTest( ) {
    java.util.concurrent.TimeUnit tu = lookupEnum(TimeUnit.class, 3);
    System.out.println(tu);
}

答案 6 :(得分:1)

这就是我使用Proguard在Android上所做的事情

public enum SomeStatus {
    UNINITIALIZED, STATUS_1, RESERVED_1, STATUS_2, RESERVED_2, STATUS_3;//do not change order

    private static SomeStatus[] values = null;
    public static SomeStatus fromInteger(int i) {
        if(SomeStatus.values == null) {
            SomeStatus.values = SomeStatus.values();
        }
        if (i < 0) return SomeStatus.values[0];
        if (i >= SomeStatus.values.length) return SomeStatus.values[0];
        return SomeStatus.values[i];
    }
}

很短,我不必担心在Proguard中出现异常

答案 7 :(得分:0)

public enum Suit implements java.io.Serializable, Comparable<Suit>{
  spades, hearts, diamonds, clubs;
  private static final Suit [] lookup  = Suit.values();
  public Suit fromOrdinal(int ordinal) {
    if(ordinal< 1 || ordinal> 3) return null;
    return lookup[value-1];
  }
}

测试类

public class MainTest {
    public static void main(String[] args) {
        Suit d3 = Suit.diamonds;
        Suit d3Test = Suit.fromOrdinal(2);
        if(d3.equals(d3Test)){
            System.out.println("Susses");
        }else System.out.println("Fails");
    }
}

如果您拥有更高效的代码,我感谢您与我们分享,我的枚举非常庞大且经常被呼叫数千次。

答案 8 :(得分:0)

所以一种方法是ExampleEnum valueOfOrdinal = ExampleEnum.values()[ordinal];可行且容易, 如前所述,ExampleEnum.values()为每个调用返回一个新的克隆数组。那可能是不必要的昂贵。我们可以像ExampleEnum[] values = values()这样缓存数组来解决这个问题。允许修改我们的缓存数组也是“危险的”。有人可以写ExampleEnum.values[0] = ExampleEnum.type2;,所以我将使用不做额外复制的访问器方法将其设为私有。

private enum ExampleEnum{
    type0, type1, type2, type3;
    private static final ExampleEnum[] values = values();
    public static ExampleEnum value(int ord) {
        return values[ord];
    }
}

您将使用ExampleEnum.value(ordinal)来获取与ordinal关联的枚举值

答案 9 :(得分:0)

您可以定义一个简单的方法,例如:

public enum Alphabet{
    A,B,C,D;

    public static Alphabet get(int index){
        return Alphabet.values()[index];
    }
}

并像这样使用它:

System.out.println(Alphabet.get(2));

答案 10 :(得分:0)

安全第一(与Kotlin合作)

// Default to null
EnumName.values().getOrNull(ordinal)

// Default to a value
EnumName.values().getOrElse(ordinal) { EnumName.MyValue }

答案 11 :(得分:-2)

每个枚举都有name(),它给出一个名为enum member的字符串。

鉴于enum Suit{Heart, Spade, Club, Diamond}Suit.Heart.name()会提供Heart

每个枚举都有一个valueOf()方法,它采用枚举类型和字符串来执行相反的操作:

Enum.valueOf(Suit.class, "Heart")返回Suit.Heart

为什么有人会使用序数超出我的范围。它可能要快几纳秒,但是如果枚举成员发生变化则不安全,因为另一个开发人员可能不知道某些代码依赖于序数值(特别是在问题中引用的JSP页面中,网络和数据库开销完全占主导地位)时间,不使用字符串上的整数。)