序數(shù)索引是指依賴于枚舉成員在枚舉中的序數(shù)(ordinal方法返回值)來進行數(shù)組索引,如:
public class Herb {
public enum Type {
ANNUAL, PERENNTAL, BIENNIAL
}
private final String name;
private final Type type;
Herb(String name, Type type) {
this.name = name;
this.type = type;
}
@Override
public String toString() {
return name;
}
public static void main(String[] args) {
// 將集合放到一個按照類型的序數(shù)進行索引的數(shù)組中來實現(xiàn) 替換
Herb[] garden = {new Herb("一年生1", Type.ANNUAL), new Herb("一年生2", Type.ANNUAL),
new Herb("兩年生1", Type.BIENNIAL), new Herb("兩年生2", Type.BIENNIAL),
new Herb("多年生1", Type.PERENNTAL), new Herb("多年生2", Type.PERENNTAL)};
Set<Herb>[] herbsByType = (Set<Herb>[])new Set[Herb.Type.values().length];
for(int i = 0;i<herbsByType.length;i++){
herbsByType[i] = new HashSet<Herb>();
}
for(Herb h:garden){
herbsByType[h.type.ordinal()].add(h);
}
for (int i = 0; i < herbsByType.length; i++) {
System.out.printf("%s: %s%n", Herb.Type.values(), herbsByType[i]);
}
}
}
結果:
[Ltest.Herb$Type;@76e704e1: [一年生1, 一年生2]
[Ltest.Herb$Type;@7a507369: [多年生2, 多年生1]
[Ltest.Herb$Type;@37c9313b: [兩年生1, 兩年生2]
這種方法的確可行,但是隱藏著許多問題。因為數(shù)組不能與泛型兼容。程序需要進行未受檢的轉(zhuǎn)換,并且不能正確無誤地進行編譯。因為數(shù)組不知道它的索引代表著什么,你必須手工標注這些索引的輸出。但是這種方法最嚴重的問題在于,當你訪問一個按照枚舉的序數(shù)進行索引的數(shù)組時,使用正確的int值就是你的職責了;int不能提供枚舉的類型安全。你如果使用了錯誤的值,程序就會悄然地完成錯誤的工作,或者幸運的話就會拋出ArrayIndexOutOfBoundException異常。
對于上述問題,java.util.EnumMap是一種非??焖俚腗ap實現(xiàn)專門用于枚舉的鍵。修改后:
Herb[] garden = {new Herb("一年生1", Type.ANNUAL), new Herb("一年生2", Type.ANNUAL),
new Herb("兩年生1", Type.BIENNIAL), new Herb("兩年生2", Type.BIENNIAL),
new Herb("多年生1", Type.PERENNTAL), new Herb("多年生2", Type.PERENNTAL)};
Map<Herb.Type, Set<Herb>> herbsByType = new EnumMap<Herb.Type,Set<Herb>>(Herb.Type.class);
for(Herb.Type t:Herb.Type.values()){
herbsByType.put(t, new HashSet<Herb>());
}
for(Herb h:garden){
herbsByType.get(h.type).add(h);
}
System.out.println(herbsByType);
}```
結果:{ANNUAL=[一年生1, 一年生2], PERENNTAL=[多年生1, 多年生2], BIENNIAL=[兩年生1, 兩年生2]}
這段程序更簡短,更清楚,也更安全,運行速度方面可以與使用序數(shù)的程序相媲美。它沒有不安全的轉(zhuǎn)換;不必手工標注出這些索引的輸出,因為映射鍵知道如何將自身翻譯成可打印的字符串的枚舉;計算數(shù)組索引時也不可能出錯。EnumMap在運行速度方面之所以能與通過序數(shù)索引的數(shù)組相媲美,是因為EnumMap在內(nèi)部使用了這種數(shù)組。但是它對程序員隱藏了這種思想細節(jié),集Map的豐富功能和類型安全與數(shù)組的快速于一身。注意EnumMap構造器采用鍵類型的Class對象:這是一個有限制的類型令牌(bounded type token),它提供了運行時的泛型信息。
附EnumMap的put和get方法
```public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum)key).ordinal()]) : null);
}```
以上描述的為一維的關系,如果表示這種關系是多維的,那么就是用EnumMap<..., EnumMap<...>>來實現(xiàn),應用程序程序員在一般情況下都不使用Enum.ordinal,即使要用也很少,因此這是一種特殊情況。
總結:
***最好不要使用序數(shù)來索引數(shù)組,而是使用EnumMap。***