首页 文章

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

提问于
浏览
265

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

如何将序数转换为 ReportTypeEnum

使用Java 6 SE .

9 回答

  • 544

    要将序数转换为其枚举represantation,您可能希望这样做:

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

    请注意数组边界 .

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

    Code example on how to cache values() .


    编辑此答案以包括评论中给出的反馈

  • -2

    这几乎肯定是 a bad idea . 当然,如果序数被事实上持久化(例如因为某人已经为URL添加了书签) - 这意味着您将来必须始终保留 enum 顺序,这对于维护人员的编码可能并不明显 .

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

  • 6

    如果我将要使用 values()

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

    同时wherever.java:

    Suit suit = Suit.values[ordinal];
    

    注意阵列界限 .

  • 81

    您可以使用静态查找表:

    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);
      }
    }
    
  • 133

    我同意大多数人使用序数可能是一个坏主意 . 我通常通过给枚举一个私有构造函数来解决这个问题,该构造函数可以采用例如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;
        }
    
    }
    

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

  • 0

    这就是我使用的 . 我并没有假装它比上面简单的解决方案更“有效” . 当在上面的解决方案中使用无效的序数值时,它所做的是提供比“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
    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");
        }
    }
    

    如果你有更高效的代码,我很感激你与我们分享,我的枚举是巨大的,不断被召唤数千次 .

  • 0

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

    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中有例外

  • 4

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

    鉴于 enum Suit{Heart, Spade, Club, Diamond}Suit.Heart.name() 将给出 Heart .

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

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

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

相关问题