如何从Java中的索引获取枚举值?


96

我在Java中有一个枚举:

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

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

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

我该怎么办?


12
在计算机科学中,索引从0开始,而不是1 ;-)
fredoverflow 2011年

1
你确定你要?通常,除了实现低级数据结构(然后使用替代机制,例如名称,以实现持久性)之外,您不应该碰序。
汤姆·哈特芬

您也可以在java.util.Calendar类中使用常量。它们在1月至12月的编号为0-11,请注意12,因为这是12月(与阴历有关)。但是我很好奇,为什么要重新发明JRE中已经“存货”的月份常数呢?
克里斯·奥尔德里奇

2FredOverflow:同意,我使用了错误的索引。2Tom Hawtin:是的,我确定。我使用某些框架来持久化数据,然后返回整数索引,而不是枚举。2克里斯·奥尔德里奇(Chris Aldrich):这只是一个虚拟的例子,与实际情况不符。
jk_ 2011年

顺便说一句,Java 8和更高版本Month内置了一个枚举。
罗勒·布尔克

Answers:


229

试试这个

Months.values()[index]

37
请注意,这将每次都克隆values数组的副本,因此,如果在性能敏感代码的内部循环中调用此数组,则可能需要创建一个静态副本并使用它。
Christopher Barber 2013年

1
我很困惑,那为什么我不想使用数组呢?
Anudeep Samaiya 2015年

@AnudeepSamaiya可能是我们想在代码中使用适当的枚举常量(Months.JAN),而不是在各处使用months [1]。
哈里·乔伊

@Christopher Barber这是“制作静态副本”的public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};Months i = ALL.get(index)
一句话

简单地使用Months.values()。clone()会更容易,或者如果您对可变性抱有偏执,将其包装在不可变的列表中(请参阅收藏集)
Christopher Barber

20

这是三种方法。

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

}

5
public static可变的(数组和非final)。真是的 并且IllegalArgumentException比返回null炸弹更有意义。
Tom Hawtin-大头钉

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;
}

在我的主要公司内,我得到了所需的国家

public static void main(String[] args) {
   int i = Countries.listGetLastIndex();
   Countries currCountry = Countries.getCountry(i);
}

将currCountry设置为最后一个国家,在本例中为Countrys.KENTUCKY。

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


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);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.