1. 程式人生 > >淺談在Java開發中的列舉的作用和用法

淺談在Java開發中的列舉的作用和用法

列舉(enum),是指一個經過排序的、被打包成一個單一實體的項列表。一個列舉的例項可以使用列舉項列表中任意單一項的值。列舉在各個語言當中都有著廣泛的應用,通常用來表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量。Java從JDK5開始,引入了對列舉的支援。

在枚舉出現之前,如果想要表示一組特定的離散值,往往使用一些常量。例如:

package com.fhp.enumexample;

public class Entity {
	
	public static final int VIDEO = 1;//視訊
	public static final int AUDIO = 2;//音訊
	public static final int TEXT = 3;//文字
	public static final int IMAGE = 4;//圖片
	
	private int id;
	private int type;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public int getType() {
		return type;
	}
	public void setType(int type) {
		this.type = type;
	}
	
	
}

當然,常量也不僅僅侷限於int型,諸如char和String等也是不在少數。然而,無論使用什麼樣的型別,這樣做都有很多的壞處。這些常量通常都是連續、有無窮多個值的量,而類似這種表示類別的量則是離散的,並且通常情況下只有有限個值。用連續的量去表示離散量,會產生很多問題。例如,針對上述的Entity類,如果要對Entity物件的type屬性進行賦值,一般會採用如下方法:

	Entity e = new Entity();
	e.setId(10);
	e.setType(2);
這樣做的缺點有:(1)程式碼可讀性差、易用性低。由於setType()方法的引數是int型的,在閱讀程式碼的時候往往會讓讀者感到一頭霧水,根本不明白這個2到底是什麼意思,代表的是什麼型別。當然,要保證可讀性,還有這樣一個辦法:
e.setType(Entity.AUDIO);

而這樣的話,問題又來了。這樣做,客戶端必須對這些常量去建立理解,才能瞭解如何去使用這個東西。說白了,在呼叫的時候,如果使用者不到Entity類中去看看,還真不知道這個引數應該怎麼傳、怎麼調。像是setType(2)這種用法也是在所難免,因為它完全合法,不是每個人都能夠建立起用常量名代替數值,從而增加程式可讀性、降低耦合性的意識。

(2)型別不安全。在使用者去呼叫的時候,必須保證型別完全一致,同時取值範圍也要正確。像是setType(-1)這樣的呼叫是合法的,但它並不合理,今後會為程式帶來種種問題。也許你會說,加一個有效性驗證嘛,但是,這樣做的話,又會引出下面的第(3)個問題。

(3)耦合性高,擴充套件性差。假如,因為某些原因,需要修改Entity類中常量的值,那麼,所有用到這些常量的程式碼也就都需要修改——當然,要仔細地修改,萬一漏了一個,那可不是開玩笑的。同時,這樣做也不利於擴充套件。例如,假如針對類別做了一個有效性驗證,如果類別增加了或者有所變動,則有效性驗證也需要做對應的修改,不利於後期維護。


列舉就是為了這樣的問題而誕生的。它們給出了將一個任意項同另一個項相比較的能力,並且可以在一個已定義項列表中進行迭代。列舉(在Jave中簡稱為enum)是一個特定型別的類。所有列舉都是Java中的新類java.lang.Enum的隱式子類。此類不能手工進行子類定義。一個簡單的列舉可以是這樣:

package com.fhp.enumexample;

public enum TypeEnum {
	VIDEO, AUDIO, TEXT, IMAGE
}

上面的Entity類就可以改成這樣:

package com.fhp.enumexample;

public class Entity {
	
	private int id;
	private TypeEnum type;
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
		
	public TypeEnum getType() {
		return type;
	}
	public void setType(TypeEnum type) {
		this.type = type;
	}
}

在為Entity物件賦值的時候,就可以這樣:
Entity e = new Entity();
e.setId(10);
e.setType(TypeEnum.AUDIO);

怎麼看,都是好了很多。在呼叫setType()時,可選值只有四個,否則會出現編譯錯誤,因此可以看出,列舉是型別安全的,不會出現取值範圍錯誤的問題。同時,客戶端不需要建立對列舉中常量值的瞭解,使用起來很方便,並且可以容易地對列舉進行修改,而無需修改客戶端。如果常量從列舉中被刪除了,那麼客戶端將會失敗並且將會收到一個錯誤訊息。列舉中的常量名稱可以被列印,因此除了僅僅得到列表中項的序號外還可以獲取更多資訊。這也意味著常量可用作集合的名稱,例如HashMap。

因為在Java中一個列舉就是一個類,它也可以有屬性和方法,並且實現介面。只是所有的列舉都繼承自java.lang.Enum類,因此enum不可以再繼承其他的類。

下面給出在列舉中宣告屬性和方法的示例:

package com.fhp.enumexample;

public enum TypeEnum {
	VIDEO(1), AUDIO(2), TEXT(3), IMAGE(4);
	
	int value;
	
	TypeEnum(int value) {
		this.value = value;
	}
	
	public int getValue() {
		return value;
	}
}

在這個列舉中,每個列舉的值都有一個對應的int型欄位,而且不同的列舉值也會有不同的int數值。同時,它和普通的類一樣,可以宣告構造器和各種各樣的方法。如:
TypeEnum type = TypeEnum.TEXT;//type的value屬性值為3。
System.out.println(type.getValue());//螢幕輸出3。
如果要為每個列舉值指定屬性,則在列舉中必須宣告一個引數為屬性對應型別的構造方法(不能是public)。否則編譯器將給出The constructor TypeEnum(int, String) is undefined的錯誤。在此例中,屬性為int型,因此構造方法應當為int型。除此之外,還可以為列舉指定多個屬性,如:
package com.fhp.enumexample;

public enum TypeEnum {
	VIDEO(1, "視訊"), AUDIO(2, "音訊"), TEXT(3, "文字"), IMAGE(4, "影象");
	
	int value;
	String name;
	
	TypeEnum(int value, String name) {
		this.value = value;
		this.name = name;
	}
	
	public int getValue() {
		return value;
	}
	
	public String getName() {
		return name;
	}
}

enum還內建了許多方法,常用的如下:

int compareTo(E o) 
          比較此列舉與指定物件的順序。


Class<E> getDeclaringClass() 
          返回與此列舉常量的列舉型別相對應的 Class 物件。


String name() 
          返回此列舉常量的名稱,在其列舉宣告中對其進行宣告。


int ordinal() 
          返回列舉常量的序數(它在列舉宣告中的位置,其中初始常量序數為零)。


String toString()
           返回列舉常量的名稱,它包含在宣告中。


static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) 
          返回帶指定名稱的指定列舉型別的列舉常量。


static T[] values()

返回該列舉的所有值。

現在,假設要為該列舉實現一個根據整數值生成列舉值的方法,可以這樣做:

package com.fhp.enumexample;

public enum TypeEnum {
	VIDEO(1, "視訊"), AUDIO(2, "音訊"), TEXT(3, "文字"), IMAGE(4, "影象");
	
	int value;
	String name;
	
	TypeEnum(int value, String name) {
		this.value = value;
		this.name = name;
	}
	
	public int getValue() {
		return value;
	}
	
	public String getName() {
		return name;
	}

	public static TypeEnum getByValue(int value) {
		for(TypeEnum typeEnum : TypeEnum.values()) {
			if(typeEnum.value == value) {
				return typeEnum;
			}
		}
		throw new IllegalArgumentException("No element matches " + value);
	}
}

getByValue(int)即為整數值轉列舉值的方法。呼叫values()方法獲取到該列舉下的所有值,然後遍歷該列舉下面的每個值和給定的整數是否匹配,若匹配直接返回,若無匹配值則丟擲IllegalArgumentException異常,表示引數不合法,兼有有效性驗證的作用。

綜上,我們可以看到,在JDK5中新引入的列舉完美地解決了之前通過常量來表示離散量所帶來的問題,大大加強了程式的可讀性、易用性和可維護性,並且在此基礎之上又進行了擴充套件,使之可以像類一樣去使用,更是為Java對離散量的表示上升了一個臺階。因此,如果在Java中需要表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量,應當儘量捨棄常量表示的做法,而將列舉作為首要的選擇。

相關推薦

敏捷開發迭代舊版本維護

在所謂敏捷開發中會出現一個經常遇到的問題就是舊版本已經發布出去 , 新版本正在開發之中,這期間發現舊版本bug需要修改的情況? 通常的解決方法是需要新舊版本的統一修改,如果這期間涉及的新舊版本程式碼已經 變化很大就需要評估這個bug在新版本是否還要存在是否修改的問題。 進

Java web request的setAttribute()用法

一下是來自社群問答的一些回答,我整合了一下形成文章 在兩個JSP程式碼片中有這樣兩端程式: JSP1程式碼String [] test=new String[2]; test[0]="1"; test[1]="2"; request.setAttribute("test"

Android開發的MVVM模式及與MVPMVC的區別

三種架構模式的演化: 什麼是MVVM? MVVM是Model-View-ViewModel的簡寫。微軟的WPF帶來了新的技術體驗,如Silverlight、音訊、視訊、3D、動畫……,這導致了軟體UI層更加細節化、可定製化。同時,在技術層面,WPF也帶來

java整合的final方法重寫過載問題

Question 1: 子類是否可以重寫父類的final方法,答案是:不可以! 父類Person: 子類SubPerson: Question 2: 子類是否可以過載父類的final方法,答案

【遊戲開發遊戲開發常見的設計原則

依賴關系 unity 說過 srp des log gof https 類繼承   俗話說得好:“設計模式,常讀常新~”。的確,每讀一遍設計模式都會有些新的體會和收獲。馬三不才,才讀了兩遍設計模式(還有一遍是在學校學的),屬於菜鳥級別的。這次準備把閱

Java中原碼、補碼反碼

學習計算機時,對於十進位制轉二進位制大家很有所瞭解,這次講講原碼、補碼和反碼的基本概念。 原碼 原碼就是十進位制數字最原始的二進位制表示,在Java中,對於整數而言,其原碼格式為最高位為符號位,該位上1表示負數而0表示正數,剩餘位數為該數字的二進位制表示。以Java中32位int型的整數

Java 8的方法引用(Method References)

  本人接觸Java 8的時間不長,對Java 8的一些新特性略有所知。Java 8引入了一些新的程式設計概念,比如經常用到的 lambda表示式、Stream、Optional以及Function等,讓人耳目一新。這些功能其實上手並不是很難,根據別人的程式碼抄過來改一下,並不要知道內部的實現原理,也可以很熟

java成員的初始化順序(一)

類被建立之後的成員的初始化順序到底是怎麼樣的? 首先 不考慮繼承 package com; public class DemoOne { /** * 關於類的初始化順序 */ //不考慮繼承結構的情況 private static int a;

script標籤的asyncdefer

script標籤用於載入指令碼與執行指令碼,在前端開發中可以說是非常重要的標籤了。直接使用script指令碼的話,html會按照順序來載入並執行指令碼,在指令碼載入&執行的過程中,會阻塞後續的DOM渲染。 現在大家習慣於在頁面中引用各種的第三方指令碼,如果第三方服務商出現了一些小

java內部類及其作用

1.1)什麼是內部類 1.2)內部類的分類: a)成員內部類【重點】 a.1)作為內部類的成員,可以直接使用外部類的所有成員和方法,包括private a.2)外部類要訪問內部類的成員變數和方法,則需

Java開發抽象類介面都有什麼區別?

在Java軟體開發中抽象類和介面會有一個明顯的區別,具體會有哪些區別呢?下文就兩者的區別做了一個比較詳細的描述。抽象類: 1、抽象類使用abstract修飾; 2、抽象類不能例項化,即不能使用new關鍵字來例項化物件; 3、含有抽象方法(使用abstract關鍵字修飾的方法)的類是抽象類,

Java開發的坑(一) -- log4j2在SaaS專案的應用

背景介紹: 做server端開發有些年頭了,特別是開始做SaaS型別的專案時,深知log的重要性,特別是半夜三更使用者(大都是美國那邊的)遇到問題的電話打過來,這個時候沒有一個強大log,那只有抓瞎的份了。以前都是走的微軟系的開發工具,log的框架也是別人早就寫好的,所以

Android開發需要注意的安全問題

什麼是安全問題?       從黑客的角度定義,只要黑客能夠從app中找到一些方法獲取我們的原始碼根據某些明顯的欄位得到重要資訊從而修改程式以達到一定目的;竊取使用者資訊;竊取本地重要資訊間接可以

android開發的MVP模式

看到MVP,大家肯定會想什麼是MVP呢?這個我可以肯定的告訴大家MVP(Most Valuable Player)是最有價值球員的意思,這當然是開玩笑了。之所以會出現MVP這種架構模式,是因為我相信大家在開發App時,肯定會發現,Activity的負擔非常重

軟體開發的防禦式程式設計

  在軟體開發中針對使用者的輸入往往不是我們所期待的那樣(不滿足前置條件),有時候軟體內部往往也會出現一些我們不易察覺的錯誤,針對這種情況,一些人持有樂觀的態度,而另外一些人則從一個其他的事情中得到了啟發:即由防禦式駕駛而想到的防禦式程式設計。   所謂防禦式程式設計,指的就是這樣一件事情:即我們假定使用者都

Java開發IO流的用法詳細解析

練習一:在Java程式設計裡統計一個檔案calcCharNum.txt中字母‘A’和’a’出現的總次數。 package com.test;import java.io.File; import java.io.FileInputStream; import java.io.FileNot

Java開發列舉作用用法

列舉(enum),是指一個經過排序的、被打包成一個單一實體的項列表。一個列舉的例項可以使用列舉項列表中任意單一項的值。列舉在各個語言當中都有著廣泛的應用,通常用來表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量。Java從JDK5開始,引入了對列舉的

【轉載】Java開發列舉作用用法

原文http://blog.csdn.net/u014527058/article/details/52751488 列舉(enum),是指一個經過排序的、被打包成一個單一實體的項列表。一個列舉的例項可

Java開發列舉作用用法

列舉(enum),是指一個經過排序的、被打包成一個單一實體的項列表。一個列舉的例項可以使用列舉項列表中任意單一項的值。列舉在各個語言當中都有著廣泛的應用,通常用來表示諸如顏色、方式、類別、狀態等等數目有限、形式離散、表達又極為明確的量。Java從JDK5開始,引

Java的深拷貝拷貝

detail tle pac err @override 復制對象 deep har 間接   淺談Java中的深拷貝和淺拷貝(轉載) 原文鏈接: http://blog.csdn.net/tounaobun/article/details/8491392 假如說你想復制一