我在Java中有一个枚举:
public enum Months
{
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}
我想通过索引访问枚举值,例如:
Months(1) = JAN;
Months(2) = FEB;
...
我该如何做到这一点?
试试这个
Months.values()[index]
public static final ArrayList<Months> ALL = new ArrayList<Month>() {{ for (Months m : Months.values()) add(m); }};
,然后你可以使用 Months i = ALL.get(index)
访问元素。 - muelleth以下是三种方法来实现它。
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
更合理。 - Tom Hawtin - tackline我刚刚尝试了同样的方法,并得出了以下解决方案:
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;
}
}
public static String getCountry(int i) {
return list[(i - 1)];
}
public static int listGetLastIndex() {
return list.length;
}
在我的主程序中,我使用以下代码获取所需的countries对象:
public static void main(String[] args) {
int i = Countries.listGetLastIndex();
Countries currCountry = Countries.getCountry(i);
}
这段代码将把currCountry设置为最后一个国家,即Countries.KENTUCKY。
请记住,如果您使用硬编码索引来获取对象,则此代码非常容易受到ArrayOutOfBoundsExceptions的影响。
.values()
通常会提供内部(静态)数组的克隆,而不是仅仅引用。该数组可能在内部预先分配,但在static{}
块的位置(在对象有机会运行任何构造函数之前),它将被填充为null。我可能会在第一次调用get(index)
时使用.values()
,它会将数组存储起来以供后续索引,或者在构造函数中逐个填充每个值。 - alife我最近遇到了同样的问题,并使用了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);
}
getById()
方法总是可以直接查找该数组,而不需要从 .values()
中克隆一个数组(大多数人都是这样做的),或者查找内部哈希表。 - alifeenum Months {
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC;
int ordinal; // ordinal will start from 1
// cached instance used as optimization
final static Months[] values = Months.values();
static {
// ordinal is initialized based on enum natural order
int counter = 1;
for (Months m: values)
m.ordinal = counter++;
}
public static Months getMonth(int ordinal) {
return values[ordinal - 1];
}
}
Month
枚举。 - Basil Bourque