SE高階(18):枚舉類的用法和應用場景

 枚舉類簡要介紹 

     
       枚舉是Java1.5引入的新特性,通過關鍵字enum來定義枚舉類,enum關鍵字和class、interface、@interface(註解)的地位是相同的。枚舉類是一種特殊類,它和普通類一樣可以使用構造器、定義成員變量和方法,也能實現一個或多個接口。但枚舉類不能繼承其他類,因爲枚舉類默認繼承java.lang.Enum類(注:Enum是抽象類),Java是單繼承,所以不允許。

 枚舉類的特點 

  • 枚舉類的構造器默認被private修飾,如果顯式指定,也只能用private來修飾,不然會報錯。
  • 枚舉類的實例必須在第一行顯式列出,不然無法生成枚舉實例,枚舉實例就是枚舉值。
  • 枚舉值默認被public final static修飾。枚舉類默認被final修飾,無法被繼承。
  • 枚舉值可以看作靜態常量對象,除了擁有常量的特性外,還和對象一樣可以調用方法、成員變量。
  • 和普通類比起來,枚舉類對象數量在第一行就被固定下來了,不能隨意創建。
public enum Color {
	RED, GREEN, BLUE;	
}
//編譯上面枚舉類後,會生成對應的字節碼文件:Color.class
       通過上面代碼,可以看出編譯後的枚舉類和普通類大致差不多,只是用法稍有不同。我們再來看一下,列出枚舉值時無需指定類型,平時定義常量時是要指定類型的,在上面關於枚舉類的特點中,說過枚舉值就是枚舉類對象,所以列出枚舉值就是在創建對象,這會使用到構造器,這裏的構造器是默認的,這時候看一下父類代碼:
 //父類Enum的構造器 
 protected Enum(String name, int ordinal) {
        this.name = name;
        this.ordinal = ordinal;
    }
       每創建一個枚舉值就會調用上述父類構造器,生成對應的enum類型靜態常量,並且按照順序設置值,初始值爲0。總之,使用枚舉類時,只需將枚舉值看作枚舉類的對象來用就行。


 枚舉類的用法 

 boolean equals(Object other)
          當指定對象等於此枚舉常量時,返回 true。
protected  void finalize()
          枚舉類不能有 finalize 方法。
 Class<E> getDeclaringClass()
          返回與此枚舉常量的枚舉類型相對應的 Class 對象。
 int hashCode()
          返回枚舉常量的哈希碼。
 String name()
          返回此枚舉常量的名稱,在其枚舉聲明中對其進行聲明。
 int ordinal()
          返回枚舉常量的序數(它在枚舉聲明中的位置,其中初始常量序數爲零)。
 String toString()
          返回枚舉常量的名稱,它包含在聲明中。
static
<T extends Enum<T>> 
T
valueOf(Class<T> enumType,String name)
          返回帶指定名稱的指定枚舉類型的枚舉常量。


查看枚舉值的序數
		System.out.println(Color.RED.ordinal());
		System.out.println(Color.GREEN.ordinal());
		System.out.println(Color.BLUE.ordinal());
		//輸出序數
		0
		1
		2
        這裏的序數就是定義枚舉值時自動爲其生成的,理論上來說可以看作是它們的初始值,但提供的數據較少,所以要爲枚舉值附加更多屬性時,可以創建成員變量,使用構造器來賦值。其他方法的話都比較簡單,在此省略示例代碼。


枚舉類中定義變量和方法
public enum Color {
	RED, GREEN, BLUE; //列出枚舉值, 枚舉類實例
	//定義實例變量和靜態變量
	private int a = 10;
	private static int b = 100;
	//定義方法
	public int getA() {
		return this.a;
	}
	public static void main(String[] args) {
		Color.RED.a = 20;
		Color.RED.b = 101;
		Color.GREEN.a = 30;
		Color.GREEN.b = 102;
		System.out.println("RED.a = " + Color.RED.getA());
		System.out.println("GREEN.a = " + Color.GREEN.getA());
		//RED.a = 20
		//GREEN.a = 30
	}
}
         上面實例中,使用枚舉值可以調用成員變量、實例方法,靜態屬性也是共享的,和普通類對象用法差不多。如果只是這樣賦值的話,會顯得麻煩且邏輯不清晰,所以採用用構造器來給給對象賦值的用法來給枚舉值賦值,實例如下:
	RED(15), GREEN(30), BLUE(45); //爲枚舉值的實例變量賦值
	//定義實例變量
	private int a = 10;
	//枚舉類的構造器 
	private Color(int a) {
		this.a = a;
	}
	//測試
	public static void main(String[] args) {
		System.out.println(Color.RED.a);
		System.out.println(Color.GREEN.a);
		System.out.println(Color.BLUE.a);
	}
       上面只是定義了3個枚舉值,每次獲取值時就顯得很麻煩了,而且重複代碼太多,這時就可以使用values()方法返回枚舉類所有實例,轉成枚舉數組。但在Enum源碼中並沒有該方法,這個問題我也不清楚.....,改進後如下:
//使用values()來循環獲取屬性值。但獲取屬性值最好是用getXxx()來完成
	public static void main(String[] args) {
		for(Color c : Color.values()) {
			System.out.println(c.a);
		}
	}


 枚舉類應用場景 


1.最常用到的當屬常量,例如定義各類狀態時,使用枚舉類可以把相關聯的常量放在一個枚舉類中,並能根據需求來增加屬性和方法。
public enum Sex {
	MAN("男") , MALE("女");
	private String sex;
	private Sex(String sex) {
		this.sex = sex;
	}
	//重寫toString(),返回枚舉值的sex屬性
	@Override 
	public String toString() {
		return this.sex;
	}
	
	public static void main(String[] args) {
		System.out.println(Sex.MAN.toString());
		System.out.println(Sex.MALE.toString());
		//輸出結果
		男
		女
		
	}
相較於常量而言,枚舉類可以另加靈活化,還能對常量進行統一管理。


2.可以在switch語句使用枚舉類,switch可以自動檢查枚舉值是否屬於傳入的枚舉類
	public static void main(String[] args) {
		//得到枚舉數組
		SeasonEnum[] se =  SeasonEnum.values();
		//隨機獲得其中一個枚舉
		SeasonEnum rand = Test.getRandomEnum(se);
		switch(rand) {
			case SPRING:
				System.out.println(rand + ", 是" + rand.getSeason());
			break;
			case SUMMER:
				System.out.println(rand + ", 是" + rand.getSeason());
				break;
			case AUTUMN:
				System.out.println(rand + ", 是" + rand.getSeason());
				break;
			case WINTER:
				System.out.println(rand + ", 是" + rand.getSeason());
				break;
		}
					
	}
	/** 根據指定的枚舉數組來隨機獲得其中一個枚舉 */
	public static <T extends Enum> T getRandomEnum(T[] enumArr) {
		int index = (int)(Math.random() * enumArr.length); //生成的下標在枚舉數組長度範圍之內
		T rs = enumArr[index];
		return rs;
	}


3.枚舉類可以在接口中定義,也可以定義在類裏面,訪問權限的使用和內部類一樣,等於使用內部類來維護一些常量的使用。
//能定義在接口中
interface testEnum{
	enum State{
		ON, OFF;
	}
}
//定義成內部枚舉類
public class Test {
	enum State{
		ON, OFF;
	}
}


4.除了以上這些,枚舉還能應用於集合:EnumSet和EnumMap,Set的底層是採用Map存儲key值來實現的,所以EnumSet的值和EnumMap的key一樣是需要枚舉類型,但Map的value類型就隨意了。  由於枚舉集合基本用不了,所以沒有給出例子,如果有需要,可以自行查詢相關資料。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章