Java基礎--列舉

鐵甲小寶-卡布達發表於2019-04-11

本文主要講解Java列舉的使用以及與使用常量的區別,由於本人水平有限,寫作之前參考了幾位大神的文章,對列舉的應用有了更深的理解。特記錄下本文章,以供自己翻閱。
參考文章地址:
https://blog.csdn.net/zyhlwzy/article/details/79045066
https://blog.csdn.net/myzksky/article/details/81150199
https://blog.csdn.net/yin_pisces/article/details/52050427

一、版本歷史

列舉(Enum)是JDK1.5版本新增的特性,1.5版本新增的特性還有泛型,For-each。JDK 1.6版本之後,switch case語句支援列舉型別的判斷。

二、什麼是列舉

列舉(Enum)是一種特殊的資料型別,它即是一種類(class)型別又比這個型別多了些特殊的約束。這些約束使其類更加的安全,方便使用。

1.建立一個列舉類

enum UserType{
    USER("USER","內部使用者",1),CUSTOMER("CUSTOMER","消費者",2),PARTNER("PARTNER","合作商",3);
    private String userType;
   	private String typeName;
    private Integer typeIndex;

    private UserType(String userType,String typeName,Integer typeIndex){
       this.userType=userType;
       this.typeName=typeName;
       this.typeIndex=typeIndex;
    }
	// get set 方法
	
    @Override  
    public String toString() {  
        return this.userType+"_"+this.typeName;  

	};
	System.out.println(UserType.USER.getTypeName());  // 內部使用者
    System.out.println(UserType.USER);	// USER  			沒有複寫toString()方法
    System.out.println(UserType.USER);	// USER_內部使用者   	複寫了toString()方法

列舉是一個特殊的類,它也有例項欄位、構造器和方法。預設無參構造器不能夠被宣告並且所有的構造器必須被private修飾,列舉例項用","隔開,序列的最後用";"結束

建立一個列舉類要使用關鍵字 enum,隱藏的含義為該列舉類自動繼承了java.lang.Enum<T>(抽象泛型類),只能實現介面而不能繼承,Java編譯器在編譯時做了這個轉換

enum UserType extends Eunum<UserType>{
    // something
};

實際上每一個繼承自Enum<T>的列舉允許定義泛型類、介面和方法,通過這種方式可以讓列舉型別的例項引數化或者型別引數化。比如:

public<T extends Enum< ? >> void performAction(final T instance) {
    // Perform some action here
}

在上面的宣告中,型別T被約定為任意列舉型別的例項並且Java編譯器將會對其做驗證

2.實現介面

interface IsUser{
	boolean ifUser();
}

兩種實現方式:

enum UserType implements IsUser{
	 USER("USER",true),CUSTOMER("CUSTOMER",true)	
	private String userType;
	private boolean isUser;
	
	UserType(String userType,boolean isUser){
		this.userType=userType;
		this.isUser=isUser;
	}
	boolean ifUser(){
		return this.isUser;
	}
}

System.out.println(UserType.USER.isUser());  //true

enum UserType implements IsUser{
	 USER("USER"){
        @Override
        public boolean isUser() {
            return true;
        }
    },CUSTOMER("CUSTOMER"){
    	 @Override
        public boolean isUser() {
            return false;
        }
    };
	private String userType;
	private boolean isUser;
	
	UserType(String userType,boolean isUser){
		this.userType=userType;
		this.isUser=isUser;
	}
}

System.out.println(UserType.USER.isUser());  //true

③使用介面組織列舉


public interface IsUser{  
    enum UserType implements IsUser{  
        USER,CUSTOMER;  
    }   
}

System.out.println(IsUser.UserType.USER);  // USER

3.列舉中的方法

基礎類 Enum<T>為自動繼承它的列舉例項提供了一些非常有用的方法。

方法 描述
String name() 返回列舉宣告宣告的列舉常量的名稱
int ordinal() 返回列舉常量的次序(即列舉宣告時的位置,初始常量分配的位置是0)

Java編譯器為每個列舉型別自動生成兩個更有用的靜態方法(讓我們將這個特殊的列舉型別假設為T)。

方法 描述
T[] values() 返回列舉T所宣告的所有常量
T valueOf(String name) 返回指定名稱的列舉常量
 System.out.println(UserType.valueOf("USER"));		// 呼叫toString方法 
 System.out.println(UserType.USER.ordinal());		// 0

上面程式碼中valueOf()的引數值為 例項名的字串形式不是該例項的變數值

4.專用集合EnumSet和EnumMap

和所有其他類一樣,列舉的例項也可以和標準Java集合庫一起使用。然而,某些集合型別針對列舉做了優化,並且在大多數情況下推薦使用這些優化過後的集合代替通用的集合。

我們首先來看一下EnumSet集合。EnumSet集合是常規的集合優化過後高效儲存列舉型別的一個集合,EnumSet不能夠使用構造器進行例項化,但是它提供了很多非常有用的工廠方法。

// allOf工廠方法建立的EnumSet<T>例項就包含了所有列舉型別所列舉的常量:
final Set<DaysOfTheWeek> enumSetAll = EnumSet.allOf(DaysOfTheWeek.class);

//noneOf工廠方法建立的是一個空的EnumSet<T>例項
final Set<DaysOfTheWeek> enumSetNone = EnumSet.noneOf(DaysOfTheWeek.class);

//使用of工廠方法,可以指定列舉型別中那些列舉常量應該包含在EnumSet<T>中:
final Set< DaysOfTheWeek > enumSetSome = EnumSet.of(
    DaysOfTheWeek.SUNDAY,
    DaysOfTheWeek.SATURDAY
);

EnumMap<T, ?>是最接近於一般的map的,唯一的不同就是EnumMap<T, ?>的key是列舉型別的列舉常量

final Map<DaysOfTheWeek, String> enumMap = new EnumMap<>(UserType.class);
enumMap.put(UserType.USER, "Lundi");

三、列舉和常量的比較

使用常量時

  • 常量作為引數時,是String,int等弱型別,開發人員可以傳入沒有在常量介面裡定義的值,這個問題無法通過編譯器發現。
  • 由於開發人員可以直接寫常量,所以不能用==對比,只能用equals對比,不能優化效能。
  • 開發人員沒有參考資料時,不可能知道某個int型別的引數到底應該賦什麼內容。
  • 編譯時,是直接把常量的值編譯到類的二進位制程式碼裡,常量的值在升級中變化後,需要重新編譯引用常量的類,因為裡面存的是舊值。
  • 如果常量類的構造器不私有,無法限制開發員繼承/實現介面,開發員能夠在子介面裡繼續新增常量.而這些常量可能得不到祖先層的支援。

使用列舉時

  • 私有建構函式,避免被繼承和擴充套件。
  • 定義方法的引數時,必須用列舉常量類型別,如上面的Constant,這樣就轉變成了強型別,不會出現弱型別引用的問題。
  • 常量值地址唯一,可以用==直接對比,效能會有提高。
  • 編譯時,沒有把常量值編譯到程式碼裡,即使常量的值發生變化,也不會影響引用常量的類。

相關文章