一:枚舉類
枚舉是JDK1.5添加的,在枚舉類型出來之前,我們都是以定義常量來代替,比如:

這種定義常量的方式也是有一些不足的,如int值相同的情況下,編譯期并不會提示我們的,是以很容易造成混淆。
定義枚舉類的一般文法:任意兩個枚舉成員不能具有相同的名稱,多個枚舉成員之間使用逗号分隔,枚舉表示的類型其取值是必須有限的
二:枚舉類原理
把剛才定義的Date枚舉類編譯後再反編譯class檔案來看一下:
可以看到,使用關鍵字enum定義的枚舉類型,在編譯期後,也将轉換成為一個實實在在的類,而在該類中,會存在每個在枚舉類型中定義好變量的對應執行個體對象,如上述的ONE枚舉類型對應public static final Date ONE;,同時編譯器會為該類建立兩個方法,分别是values()和valueOf()。
- 枚舉類實際上也是一個類,預設繼承于java.lang.Enum類,并且此類是final的,不可被繼承,又由于java是單繼承已經預設繼承Enum是以我們定義的Date枚舉類是不允許繼承其他類的。
- 預設生成私有構造函數,隻能由虛拟機去建立,不允許外部直接建立枚舉類對象的。
- 定義的枚舉實際上是枚舉類型的常量。
java.lang.Enum源碼
下面例子測試其方法:
運作輸出:
Values()方法與ValueOf()方法
values()方法和valueOf(String name)方法是編譯器生成的static方法,在Enum類中并沒出現values()方法,但valueOf()方法還是有出現的,隻不過編譯器生成的valueOf()方法需傳遞一個name參數,而Enum自帶的靜态方法valueOf()則需要傳遞兩個方法,其實,編譯器生成的valueOf方法最終還是調用了Enum類的valueOf方法:
運作輸出:
values()方法的作用就是擷取枚舉類中的所有變量,并作為數組傳回。
valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據名稱擷取枚舉變量。
三:枚舉類使用
- enum 與 class、interface 具有相同地位,但是不能繼承與被繼承,也不能建立執行個體,隻能由JVM去建立。
- 可以實作多個接口,也可以擁有構造器、成員方法、成員變量。
實作接口
定義構造函數
注意:隻能是私有的構造函數或預設
定義成員方法和成員變量
EnumMap
java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumMap繼承了AbstractMap類,是以EnumMap具備一般map的使用方法,主要通過一個儲存key的數組K[] keyUniverse和一個儲存value的數組Object[] vals來操作。
源碼:
下面例子測試其方法:
運作輸出:
{ONE=1, THREE=3}
EnumSet
EnumSet是與枚舉類型一起使用的專用 Set 集合,EnumSet 中所有元素都必須是枚舉類型。注意EnumSet不允許使用 null 元素。試圖插入 null 元素将抛出 NullPointerException,但試圖測試判斷是否存在null 元素或移除 null 元素則不會抛出異常,與大多數collection 實作一樣,EnumSet不是線程安全的,是以在多線程環境下應該注意資料同步問題。
public abstract class EnumSet> extends AbstractSet
implements Cloneable, java.io.Serializable
//元素的class
final Class elementType;
final Enum>[] universe;
private static Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
this.elementType = elementType;
this.universe = universe;
}
//建立一個具有指定元素類型的空EnumSet。
Enum>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
//建立一個指定元素類型并包含所有枚舉值的EnumSet
EnumSet result = noneOf(elementType);
result.addAll();
return result;
}
abstract void addAll();
建立一個包含參數容器中的所有元素的EnumSet
return s.clone();
}
return ((EnumSet)c).clone();
if (c.isEmpty())
throw new IllegalArgumentException("Collection is empty");
Iterator i = c.iterator();
E first = i.next();
EnumSet result = EnumSet.of(first);
while (i.hasNext())
result.add(i.next());
return result;
}
}
// 初始集合包括指定集合的補集
EnumSet result = copyOf(s);
result.complement();
return result;
}
// 建立一個包括參數中所有元素的EnumSet
EnumSet result = noneOf(e.getDeclaringClass());
result.add(e);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
return result;
}
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
return result;
}
public static > EnumSet of(E e1, E e2, E e3, E e4,
E e5)
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);
return result;
}
@SafeVarargs
EnumSet result = noneOf(first.getDeclaringClass());
result.add(first);
for (E e : rest)
result.add(e);
return result;
}
// 建立一個包括枚舉值中指定範圍元素的EnumSet
if (from.compareTo(to) > 0)
throw new IllegalArgumentException(from + " > " + to);
EnumSet result = noneOf(from.getDeclaringClass());
result.addRange(from, to);
return result;
}
abstract void addRange(E from, E to);
@SuppressWarnings("unchecked")
return (EnumSet) super.clone();
throw new AssertionError(e);
}
}
abstract void complement();
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
throw new ClassCastException(eClass + " != " + elementType);
}
return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(elementType);
}
}
下面例子測試其方法:
建立EnumSet并不能使用new關鍵字,因為它是個抽象類,而應該使用其提供的靜态工廠方法,EnumSet的靜态工廠方法比較多,如下:
運作輸出: