本文轉載自http://www.javashuo.com/article/p-poapgxnl-ka.htmljava
JDK1.5引入了新的類型——枚舉。在 Java 中它雖然算個「小」功能,卻給個人開發帶來了「大」方便。ide
大師兄我又加上本身的理解,來幫助各位理解一下。函數
用法一:常量學習
在JDK1.5 以前,咱們定義常量都是: public static final.... 。如今好了,有了枚舉,能夠把相關的常量分組到一個枚舉類型裏,並且枚舉提供了比常量更多的方法。 測試
Java代碼 this
public enum Color { .net
RED, GREEN, BLANK, YELLOW 對象
} blog
用法二:switch排序
JDK1.6以前的switch語句只支持int,char,enum類型,使用枚舉,能讓咱們的代碼可讀性更強。
Java代碼
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
用法三:向枚舉中添加新方法
若是打算自定義本身的方法,那麼必須在enum實例序列的最後添加一個分號。並且 Java 要求必須先定義 enum 實例。
Java代碼
public enum Color {
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("×××", 4);
// 成員變量
private String name;
private int index;
// 構造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 普通方法
public static String getName(int index) {
for (Color c : Color.values()) {
if (c.getIndex() == index) {
return c.name;
}
}
return null;
}
// get set 方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
用法四:覆蓋枚舉的方法
下面給出一個toString()方法覆蓋的例子。
Java代碼
public enum Color {
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("×××", 4);
// 成員變量
private String name;
private int index;
// 構造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//覆蓋方法
@Override
public String toString() {
return this.index+"_"+this.name;
}
}
用法五:實現接口
全部的枚舉都繼承自java.lang.Enum類。因爲Java 不支持多繼承,因此枚舉對象不能再繼承其餘類。
Java代碼
public interface Behaviour {
void print();
String getInfo();
}
public enum Color implements Behaviour{
RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("×××", 4);
// 成員變量
private String name;
private int index;
// 構造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
//接口方法
@Override
public String getInfo() {
return this.name;
}
//接口方法
@Override
public void print() {
System.out.println(this.index+":"+this.name);
}
}
用法六:使用接口組織枚舉
Java代碼
public interface Food {
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,LATTE,CAPPUCCINO
}
enum Dessert implements Food{
FRUIT, CAKE, GELATO
}
}
/**
* 測試繼承接口的枚舉的使用(by 大師兄 or 大溼胸。)
*/
private static void testImplementsInterface() {
for (Food.DessertEnum dessertEnum : Food.DessertEnum.values()) {
System.out.print(dessertEnum + " ");
}
System.out.println();
//我這地方這麼寫,是由於我在本身測試的時候,把這個coffee單獨到一個文件去實現那個food接口,而不是在那個接口的內部。
for (CoffeeEnum coffee : CoffeeEnum.values()) {
System.out.print(coffee + " ");
}
System.out.println();
//搞個實現接口,來組織枚舉,簡單講,就是分類吧。若是大量使用枚舉的話,這麼幹,在寫代碼的時候,就很方便調用啦。
//還有就是個「多態」的功能吧,
Food food = Food.DessertEnum.CAKE;
System.out.println(food);
food = CoffeeEnum.BLACK_COFFEE;
System.out.println(food);
}
運行結果
用法七:關於枚舉集合的使用
java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重複;EnumMap中的 key是enum類型,而value則能夠是任意類型。關於這個兩個集合的使用就不在這裏贅述,能夠參考JDK文檔。
關於枚舉的實現細節和原理請參考:
參考資料:《ThinkingInJava》第四版
http://softbeta.iteye.com/blog/1185573
個人這篇文章,由於是轉載的,可能基本就沒有變更,致使被某人踩了一腳。以爲不符合我大師兄的性格。下面我把本身的使用理解給整理一下。
也是由於由於當時剛剛開始學習吧。把平時自覺得了解的東西都只是大概瞭解了一下,說到底,仍是自覺得了解了,其實轉眼就不知道什麼是什麼了。
出來學習,不習慣看代碼怎麼能行呢?
下面是我本身的測試代碼。
package com.lxk.enumTest;
/**
* Java枚舉用法測試
* <p>
* Created by lxk on 2016/12/15
*/
public class EnumTest {
public static void main(String[] args) {
forEnum();
useEnumInJava();
}
/**
* 循環枚舉,輸出ordinal屬性;若枚舉有內部屬性,則也輸出。(說的就是我定義的TYPE類型的枚舉的typeName屬性)
*/
private static void forEnum() {
for (SimpleEnum simpleEnum : SimpleEnum.values()) {
System.out.println(simpleEnum + " ordinal " + simpleEnum.ordinal());
}
System.out.println("------------------");
for (TYPE type : TYPE.values()) {
System.out.println("type = " + type + " type.name = " + type.name() + " typeName = " + type.getTypeName() + " ordinal = " + type.ordinal());
}
}
/**
* 在Java代碼使用枚舉
*/
private static void useEnumInJava() {
String typeName = "f5";
TYPE type = TYPE.fromTypeName(typeName);
if (TYPE.BALANCE.equals(type)) {
System.out.println("根據字符串得到的枚舉類型實例跟枚舉常量一致");
} else {
System.out.println("大師兄代碼錯誤");
}
}
/**
* 季節枚舉(不帶參數的枚舉常量)這個是最簡單的枚舉使用實例
* Ordinal 屬性,對應的就是排列順序,從0開始。
*/
private enum SimpleEnum {
SPRING,
SUMMER,
AUTUMN,
WINTER
}
/**
* 經常使用類型(帶參數的枚舉常量,這個只是在書上不常見,實際使用仍是不少的,看懂這個,使用就不是問題啦。)
*/
private enum TYPE {
FIREWALL("firewall"),
SECRET("secretMac"),
BALANCE("f5");
private String typeName;
TYPE(String typeName) {
this.typeName = typeName;
}
/**
* 根據類型的名稱,返回類型的枚舉實例。
*
* @param typeName 類型名稱
*/
public static TYPE fromTypeName(String typeName) {
for (TYPE type : TYPE.values()) {
if (type.getTypeName().equals(typeName)) {
return type;
}
}
return null;
}
public String getTypeName() {
return this.typeName;
}
}
}
而後是測試的結果圖:
簡單的例子,你們基本都用過,看不懂的基本都是第二個例子。能夠看到,在第二個例子裏面,後面帶有參數,其實能夠這麼理解。
enum這個關鍵字,能夠理解爲跟class差很少,這也個單獨的類。能夠看到,上面的例子裏面有屬性,有構造方法,有getter,也能夠有setter,可是通常都是構造傳參數。還有其餘自定義方法。那麼在這些東西前面的,以逗號隔開的,最後以分號結尾的,這部分叫作,這個枚舉的實例。也能夠理解爲,class new 出來的實例對象。這下就好理解了。只是,class,new對象,能夠本身隨便new,想幾個就幾個,而這個enum關鍵字,他就不行,他的實例對象,只能在這個enum裏面體現。也就是說,他對應的實例是有限的。這也就是枚舉的好處了,限制了某些東西的範圍,舉個栗子:一年四季,只能有春夏秋冬,你要是字符串表示的話,那就海了去了,可是,要用枚舉類型的話,你在enum的大括號裏面把全部的選項,全列出來,那麼這個季節的屬性,對應的值,只能在裏面挑。不能有其餘的。
我上面的例子,就是根據typeName,你能夠從那些例子裏面挑選到惟一的一個TYPE類型的枚舉實例--TYPE.BALANCE。注意方法
TYPE type = TYPE.fromTypeName(typeName);
這個方法的返回類型就是這個TYPE枚舉類型的。
這下就好理解,這個枚舉是怎麼在工做了吧
再補充一下:
上面那個帶參數的枚舉類型的實例裏面其實是三個屬性,除了我自定義的typeName之外,還有2個是系統自帶的。看下面源碼的圖:
看到這裏以後,不知道你能不能理解下面圖片內說明的話:下面圖片主要說明在使用枚舉時,的規範和標準。但願能夠在實際開發時候用到
最後補充一點:
也許你知道呢,可是也許你不知道呢?我是真的不知道,測了以後才知道!!!
枚舉類型對象之間的值比較,是可使用==,直接來比較值,是否相等的,不是必須使用equals方法的喲。
具體,請參考下面的連接:
java 枚舉類比較是用==仍是equals?
2017.11.07 更新
有的老鐵,說這個switch case怎麼寫,我就在下面再囉嗦一下。
private static void testSwitchCase() {
String typeName = "f5";
//這幾行註釋呢,你能夠試着三選一,測試一下效果。
//String typeName = "firewall";
//String typeName = "secretMac";
TypeEnum typeEnum = TypeEnum.fromTypeName(typeName);
if (typeEnum == null) {
return;
}
switch (typeEnum) {
case FIREWALL:
System.out.println("枚舉名稱(即默認自帶的屬性 name 的值)是:" + typeEnum.name());
System.out.println("排序值(默認自帶的屬性 ordinal 的值)是:" + typeEnum.ordinal());
System.out.println("枚舉的自定義屬性 typeName 的值是:" + typeEnum.getTypeName());
break;
case SECRET:
System.out.println("枚舉名稱(即默認自帶的屬性 name 的值)是:" + typeEnum.name());
System.out.println("排序值(默認自帶的屬性 ordinal 的值)是:" + typeEnum.ordinal());
System.out.println("枚舉的自定義屬性 typeName 的值是:" + typeEnum.getTypeName());
break;
case BALANCE:
System.out.println("枚舉名稱(即默認自帶的屬性 name 的值)是:" + typeEnum.name());
System.out.println("排序值(默認自帶的屬性 ordinal 的值)是:" + typeEnum.ordinal());
System.out.println("枚舉的自定義屬性 typeName 的值是:" + typeEnum.getTypeName());
break;
default:
System.out.println("default");
}
}
而後,就是運行結果的截圖。
老鐵們,看完這個枚舉,你要懂個概念,那就是,這個枚舉,他是個對象,就像你定義的Student類,Person類,等等一些個類同樣。
要有這麼個概念。只要是個類,他就能夠有構造函數,能夠有屬性,能夠有方法。
對的,老鐵,你對這個屬性,構造函數啥的,有概念吧,沒有的話,我可就鬱悶啦。
而後,你就看到,這個地方有2個默認的屬性,一個是name,一個是ordinal,這2個屬性就像你定義Student類和Person類的name和age同樣,
只不過,這2個是系統自帶的屬性,不用你本身去定義啦。
你也能夠給這個枚舉類,也就是你本身聲明的枚舉,隨便加屬性。
我上面代碼例子裏面的那個TypeEnum那個枚舉,就是這麼幹的,就簡單的添加了個自定義屬性typeName,
雖然他有本身的name了,那姑且叫我這個自定義的屬性叫別名吧。
能夠看到,我例子裏面就是經過本身寫的那個構造方法給我這個自定義的屬性初始化值的。
還有,這個構造方法是不能夠,也不被運行public的,不信,你能夠試試。
還有,你不能對系統自帶的name屬性,在構造函數裏面賦值,沒有爲何。