天天看點

詳解Java中的枚舉枚舉

枚舉

在很多的程式設計語言中,枚舉是一種比較常見的原生類型,枚舉是一種比較常見的原生類型,但是在Java裡面,一直到 JDK 1.5 之後才正式引入了枚舉結構,其主要的目的是進行多例設計模式的替換。

提示:實際上,傳統的多例設計模式是在進行Java開發的過程中,不得已而使用的一種設計結構,因為需要控制對象産生個數,而傳統的多例設計模式需要通過一個具體的static方法來擷取指定類型的執行個體化對象,可是在獲得的時候必須傳入一些标記,于是很多習慣于使用枚舉結構的開發人員來說就表示嚴重的不習慣。

但是對于一直從事Java開發的工程人員來說,由于可能一直沒有使用枚舉的習慣,是以反而覺得多例設計設計模式簡單明了。

一、定義枚舉類

在 JDK 1.5 之後,如果需要定義枚舉類,那麼可以直接使用enum關鍵字來完成,而枚舉類定義的時候需要提供好若幹個執行個體化對象。

範例:定義枚舉類

enum Color{ //定義枚舉類
	RED,GREEN,BLUE; //描述枚舉對象
}
public class Test {
	public static void main(String[] args) {
		Color c = Color.RED; //直接擷取指定對象
		System.out.println(c);
	}
}

/**
	程式執行結果:RED
**/
           

此時的Color類就相當于是一個多例設計,但是與傳統的多例設計相比,此時的Color類可以直接擷取類中指定的執行個體化對象,并且避免了之前需要傳遞參數getInstance()方式來擷取。

範例:使用中文定義枚舉對象

enum Color{ //定義枚舉類
	紅色,綠色,藍色; //描述枚舉對象
}
public class Test {
	public static void main(String[] args) {
		Color c = Color.紅色; //直接擷取指定對象
		System.out.println(c);
	}
}

/**
	程式執行結果:紅色
**/
           

在Java中可以直接使用中文的形式來進行變量或者對象的聲明,是以此時使用中文完全沒有問題,在枚舉對象輸出的時候也會自動調用toString()方法,而它所傳回的預設内容就是枚舉對象的名稱。

在使用傳統多例設計設計模式進行開發的過程之中,很難全面的知道到底有多少個對象可以供使用者使用,但是如果直接使用枚舉這些資訊都可以非常直白地描述出來。

範例:擷取枚舉中的全部資料資訊

enum Color{ //定義枚舉類
	RED,GREEN,BLUE; //描述枚舉對象
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values()) {//values()可以擷取全部枚舉資訊
			System.out.print(c + "、");
		}
	}
}

/**
	程式執行結果:RED、GREEN、BLUE、
**/
           

本程式直接通過枚舉中提供的values()方法将所有的枚舉對象轉為數組的形式傳回,随後利用for-each輸出枚舉中的每一項資訊定義,在 JDK 1.5 之後,不僅追加了枚舉的結構,同時也針對于枚舉改進了switch結構。

swich進化史:
  • JDK 1.0 ~ JDK 1.4 :switch支援整型、字元型判斷;
  • JDK 1.5:switch支援枚舉判斷;
  • JDK 1.7:switch支援String的判斷;
  • JDK 1.13:switch可以結合yield實作局部傳回。

範例:在switch中使用枚舉進行判斷

enum Color{ //定義枚舉類
	RED,GREEN,BLUE; //描述枚舉對象,此處的大寫與多例設計中的大寫意義相同
}
public class Test {
	public static void main(String[] args) {
		Color c =Color.RED; //擷取枚舉對象
		switch(c) {
			case RED:
				System.out.println("【RED】紅色");
				break;
			case GREEN:
				System.out.println("【GREEN】綠色");
				break;
			case BLUE:
				System.out.println("【BLUE】藍色");
				break;
		}
	}
}

/**
	程式執行結果:【RED】紅色
**/
           

這種switch判斷僅僅在枚舉上,如果是多例設計模式,那麼沒有這樣的支援語句,隻能夠通過各種if以及對象比較的方法來完成。

二、Enum類

在Java裡面需要通過enum關鍵字來實作枚舉類的定義,但是嚴格意義上來講,使用enum關鍵字所定義的本質上相當于一個類繼承了Enum父類結構,即:如果想要研究枚舉,那麼最佳的做法就是去觀察一下Enum類的定義:

public abstract class Enum<E extends Enum<E>>//此泛型是由枚舉來控制的
extends Object
implements Constable, Comparable<E>, Serializable
           

首先可以發現,Enum類屬于一個抽象類,按照Java面向對象的設計結構來講,所有的抽象類一定要提供有相應的子類,如果子類不屬于抽象類,則一定要覆寫父類中的全部抽象方法,但是Enum類中并沒有提供抽象方法,而之是以将其定義為抽象類是因為不希望這個類直接被使用,而在Enum類中提供有如下的幾個方法:

詳解Java中的枚舉枚舉

通過定義可以發現,在枚舉的構造方法上使用了protected通路控制權限,那麼就證明了此時的枚舉中的構造方法使用了封裝定義(不管是單例設計模式還是多例設計模式,首要的要求就是構造方法私有化)。

範例:觀察Enum類中的使用

enum Color{ //定義枚舉類
	RED,GREEN,BLUE; //描述枚舉對象,此處的大寫與多例設計中的大寫意義相同
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名稱 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程式執行結果:【RED】名稱 = RED、序号 = 0
				【GREEN】名稱 = GREEN、序号 = 1
				【BLUE】名稱 = BLUE、序号 = 2
**/
           

通過以上的程式代碼就可以清楚地發現,enum定義的枚舉結構就相當于一個類繼承了Enum父類的結構。

總結:請解釋enum和Enum的差別?

  • enum是在JDK 1.5 之後提供枚舉定義的關鍵字;
  • 使用enum關鍵字定義的枚舉類從本質上就相當于定義了一個繼承Enum父類的結構。

三、擴充枚舉結構

雖然Java是在 JDK 1.5 之後才正式提供了枚舉類型,但是從其應用的角度來講,其枚舉的功能已經要比任何語言中所要提供的枚舉功能都要強大,因為傳統的枚舉僅僅是能夠定義若幹個枚舉項(對象),而在Java中可以将類的結構充分的定義在枚舉中。

1、在枚舉中定義屬性與方法

enum Color{ //定義枚舉類
	//此時類中不提供有無參的構造方法,是以每一個枚舉項(執行個體化對象)都必須明确的調用有參構造方法并傳遞參數
	RED("紅色"),GREEN("綠色"),BLUE("藍色"); //枚舉項必須寫在類的首行
	private String content; //定義屬性
	Color(String content){ //此時的枚舉類中不提供無參構造
		this.content = content;
	}
	public String toString() { //覆寫toString()方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名稱 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程式執行結果:【紅色】名稱 = RED、序号 = 0
				【綠色】名稱 = GREEN、序号 = 1
				【藍色】名稱 = BLUE、序号 = 2
**/
           

枚舉的本質就是多例設計模式,而多例設計模式裡面的首要的實作要求:類中的構造方法私有化,當在枚舉中定義構造方法的時候絕對不要使用public通路權限,否則會出現有如下的編譯錯誤。

範例:錯誤的構造方法定義

enum Color{ //定義枚舉類
	//此時類中不提供有無參的構造方法,是以每一個枚舉項(執行個體化對象)都必須明确的調用有參構造方法并傳遞參數
	RED("紅色"),GREEN("綠色"),BLUE("藍色"); //枚舉項必須寫在類的首行
	private String content; //定義屬性
	public Color(String content){ //此時的枚舉類中不提供無參構造
		this.content = content;
	}
	public String toString() { //覆寫toString()方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		for(Color c : Color.values() ) {
			System.out.println("【"+ c +"】名稱 = " + c.name() + "、序号 = " + c.ordinal());
		}	
	}
}

/**
	程式編譯結果:Illegal modifier for the enum constructor; 					only private is permitted.
**/
           

2、枚舉整體運作結構實際上是和類是相同的,那麼既然和類是相同的,是以枚舉本身也可以實作接口,而對于接口的抽象方法,可以分開實作,也可以集中實作。

範例:公共實作接口的抽象方法

interface IMessage{//定義一個擷取消息的接口
	public String getColor();//抽象方法
}
enum Color implements IMessage{ //定義枚舉類
	//此時類中不提供有無參的構造方法,是以每一個枚舉項(執行個體化對象)都必須明确的調用有參構造方法并傳遞參數
	RED("紅色"),GREEN("綠色"),BLUE("藍色"); //枚舉項必須寫在類的首行
	private String content; //定義屬性
	Color(String content){ //此時的枚舉類中不提供無參構造
		this.content = content;
	}
	public String getColor() { //公共覆寫方法
		return this.content;
	}	
}
public class Test {
	public static void main(String[] args) {
		IMessage msg = Color.RED; //擷取一個接口的子類對象
		System.out.println(msg.getColor());
	}
}

/**
	程式執行結果:紅色
**/
           

除了以上的方式之外,在枚舉中的每一個枚舉對象也可以分開來實作具體的抽象方法。

範例:每一個枚舉項實作抽象方法

interface IMessage{//定義一個擷取消息的接口
	public String getColor();//抽象方法
}
enum Color implements IMessage{ //定義枚舉類
	//此時類中不提供有無參的構造方法,是以每一個枚舉項(執行個體化對象)都必須明确的調用有參構造方法并傳遞參數
	RED{
		public String getColor() {
			return "紅色";
		}
	},GREEN{
		public String getColor() {
			return "綠色";
		}
	},BLUE{
		public String getColor() {
			return "藍色";
		}
	}; 
	
}
public class Test {
	public static void main(String[] args) {
		IMessage msg = Color.RED; //擷取一個接口的子類對象
		System.out.println(msg.getColor());
	}
}

/**
	程式執行結果:紅色
**/
           

3、在枚舉中也可以直接定義抽象方法,而對于這些抽象方法就要求每一個枚舉項都必須明确的進行覆寫。

enum Color{ //定義枚舉類
	//此時類中不提供有無參的構造方法,是以每一個枚舉項(執行個體化對象)都必須明确的調用有參構造方法并傳遞參數
	RED{
		public String getColor() {
			return "紅色";
		}
	},GREEN{
		public String getColor() {
			return "綠色";
		}
	},BLUE{
		public String getColor() {
			return "藍色";
		}
	}; 
	public abstract String getColor();//抽象方法
	
}
public class Test {
	public static void main(String[] args) {
		System.out.println(Color.BLUE.getColor());
	}
}

/**
	程式執行結果:藍色
**/
           

實際上通過以上的幾個程式的功能就可以非常清楚地發現,原來整個的枚舉從它的定義來說,是所有語言設計之最。

四、枚舉應用案例

經過一系列的分析之後我們已經清楚了枚舉的基本使用,但是随後還需要進一步的去思考,枚舉在我們的實際開發過程之中應該如何去使用呢?首先一定要清楚使用枚舉就相當于定義了一個操作的範疇,那麼既然有了操作的範疇,對于一些類的對象就有了使用的固定環境,例如:如果要定義圖書類,圖書肯定會有分類,而這個分類就可以通過枚舉來描述。

範例:使用枚舉定義圖書的範圍

enum BookType{ //定義枚舉類
	MATH("數學"),PROGRAM("軟體程式設計"),GAME("遊戲");
	private String content;
	private BookType(String content) {
		this.content = content;
	}
	public String toString() {
		return this.content;
	}
}
class Book{
	private String title;
	private String author;
	private double price;
	private BookType type;
	public Book() {
		super();
		// TODO Auto-generated constructor stub
	}
	public Book(String title, String author, double price, BookType type) {
		super();
		this.title = title;
		this.author = author;
		this.price = price;
		this.type = type;
	}
	/**
	 * @return the title
	 */
	public String getTitle() {
		return title;
	}
	/**
	 * @param title the title to set
	 */
	public void setTitle(String title) {
		this.title = title;
	}
	/**
	 * @return the author
	 */
	public String getAuthor() {
		return author;
	}
	/**
	 * @param author the author to set
	 */
	public void setAuthor(String author) {
		this.author = author;
	}
	/**
	 * @return the price
	 */
	public double getPrice() {
		return price;
	}
	/**
	 * @param price the price to set
	 */
	public void setPrice(double price) {
		this.price = price;
	}
	/**
	 * @return the type
	 */
	public BookType getType() {
		return type;
	}
	/**
	 * @param type the type to set
	 */
	public void setType(BookType type) {
		this.type = type;
	}
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		return "【圖書】名稱:" + this.title + "、作者:" + this.author + "、價格:" + this.price + "、類型:" + this.type ;
	}
}
public class Test {
	public static void main(String[] args) {
		System.out.println(new Book("高等數學" , "小賈老師" , 99.8 , BookType.MATH));
	}
}

/**
	程式執行結果:【圖書】名稱:高等數學、作者:小賈老師、價格:99.8、類型:數學
**/
           

很多同學也會覺得,即使此時不使用枚舉也可以實作,但是畢竟從枚舉産生到現在已經度過了15年的時間了,現在對于枚舉的使用早已經深入人心了。