【问题标题】:How to get Enum Value from index in Java?如何从 Java 中的索引中获取枚举值?
【发布时间】:2011-10-05 06:43:14
【问题描述】:

我有一个 Java 枚举:

public enum Months
{
    JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}

我想通过索引访问枚举值,例如

Months(1) = JAN;
Months(2) = FEB;
...

我该怎么做?

【问题讨论】:

  • 在计算机科学中,索引从 0 开始,而不是 1 ;-)
  • 您确定要这样做吗?通常,除了实现低级数据结构(然后使用名称等替代机制来实现持久性)之外,您不应触及序数。
  • 您也可以使用 java.util.Calendar 类中的常量。 1 - 12 月的编号为 0 - 11。请注意 12,因为那是 UnDecember(与农历有关)。但我只是好奇为什么要重新发明 JRE 中已经“存货”的月份常量?
  • 2FredOverflow:同意,我使用了错误的索引。 2汤姆·霍廷:是的,我确定。我用一些框架保存数据,然后我得到整数索引,而不是枚举。 2Chris Aldrich:这只是与真实案例不匹配的虚拟示例。
  • 顺便说一下,Java 8 及更高版本内置了 Month 枚举。

标签: java enums


【解决方案1】:

我最近遇到了同样的问题,并使用了 Harry Joy 提供的解决方案。 不过,该解决方案仅适用于从零开始的枚举。我也不认为它保存,因为它不处理超出范围的索引。

我最终使用的解决方案可能没有那么简单,但它完全可以保存,即使使用大枚举也不会损害代码的性能:

public enum Example {

    UNKNOWN(0, "unknown"), ENUM1(1, "enum1"), ENUM2(2, "enum2"), ENUM3(3, "enum3");

    private static HashMap<Integer, Example> enumById = new HashMap<>();
    static {
        Arrays.stream(values()).forEach(e -> enumById.put(e.getId(), e));
    }

    public static Example getById(int id) {
        return enumById.getOrDefault(id, UNKNOWN);
    }

    private int id;
    private String description;

    private Example(int id, String description) {
        this.id = id;
        this.description= description;
    }

    public String getDescription() {
        return description;
    }

    public int getId() {
        return id;
    }
}

如果你确定你的索引永远不会超出范围,并且你不想像我上面那样使用UNKNOWN,你当然也可以这样做:

public static Example getById(int id) {
        return enumById.get(id);
}

【讨论】:

    【解决方案2】:

    我只是尝试了同样的方法并想出了以下解决方案:

    public enum Countries {
        TEXAS,
        FLORIDA,
        OKLAHOMA,
        KENTUCKY;
    
        private static Countries[] list = Countries.values();
    
        public static Countries getCountry(int i) {
            return list[i];
        }
    
        public static int listGetLastIndex() {
            return list.length - 1;
        }
    }
    

    这个类有它自己的值保存在一个数组中,我使用数组来获取索引位置的枚举。如上所述,数组从 0 开始计数,如果您希望索引从 '1' 开始,只需将这两个方法更改为:

    public static String getCountry(int i) {
        return list[(i - 1)];
    }
    
    public static int listGetLastIndex() {
        return list.length;
    }
    

    在我的 Main 中,我使用

    获得所需的国家/地区对象
    public static void main(String[] args) {
       int i = Countries.listGetLastIndex();
       Countries currCountry = Countries.getCountry(i);
    }
    

    将 currCountry 设置为最后一个国家/地区,在本例中为 Country.KENTUCKY。

    请记住,如果您使用硬编码的索引来获取对象,则此代码会受到 ArrayOutOfBoundsExceptions 的极大影响。

    【讨论】:

      【解决方案3】:

      这里有三种方法。

      public enum Months {
          JAN(1), FEB(2), MAR(3), APR(4), MAY(5), JUN(6), JUL(7), AUG(8), SEP(9), OCT(10), NOV(11), DEC(12);
      
      
          int monthOrdinal = 0;
      
          Months(int ord) {
              this.monthOrdinal = ord;
          }
      
          public static Months byOrdinal2ndWay(int ord) {
              return Months.values()[ord-1]; // less safe
          }
      
          public static Months byOrdinal(int ord) {
              for (Months m : Months.values()) {
                  if (m.monthOrdinal == ord) {
                      return m;
                  }
              }
              return null;
          }
          public static Months[] MONTHS_INDEXED = new Months[] { null, JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC };
      
      }
      
      
      
      
      import static junit.framework.Assert.assertEquals;
      
      import org.junit.Test;
      
      public class MonthsTest {
      
      @Test
      public void test_indexed_access() {
          assertEquals(Months.MONTHS_INDEXED[1], Months.JAN);
          assertEquals(Months.MONTHS_INDEXED[2], Months.FEB);
      
          assertEquals(Months.byOrdinal(1), Months.JAN);
          assertEquals(Months.byOrdinal(2), Months.FEB);
      
      
          assertEquals(Months.byOrdinal2ndWay(1), Months.JAN);
          assertEquals(Months.byOrdinal2ndWay(2), Months.FEB);
      }
      
      }
      

      【讨论】:

      • public static 可变(数组和非final)。嗯。 IllegalArgumentException 比返回 null 炸弹更有意义。
      【解决方案4】:

      试试这个

      Months.values()[index]
      

      【讨论】:

      • 请注意,每次都会克隆 values 数组的副本,因此如果您在性能敏感代码的内部循环中调用它,您可能需要制作一个静态副本并使用它。
      • 我很困惑,那我为什么不想使用数组呢?
      • @AnudeepSamaiya 可能是我们想在代码中使用正确的枚举常量(Months.JAN),而不是到处使用月份[1]。
      • @Christopher Barber 这是“制作静态副本”的单行代码:public static final ArrayList&lt;Months&gt; ALL = new ArrayList&lt;Month&gt;() {{ for (Months m : Months.values()) add(m); }};,然后您可以使用 Months i = ALL.get(index) 访问元素
      • 简单地使用 Months.values().clone() 或者如果您对可变性感到偏执,将其包装在不可变列表中会更容易(请参阅集合)
      猜你喜欢
      • 1970-01-01
      • 2011-09-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-10
      • 1970-01-01
      相关资源
      最近更新 更多