本文包括:
- 枚舉由來(lái)
- 如何使用?
- 枚舉類特性
- 單例設(shè)計(jì)模式
- 定義特殊結(jié)構(gòu)枚舉
- 星期輸出中文的案例
- 枚舉類API
枚舉(enum)
1、枚舉由來(lái)
定義一個(gè)僅容許特定數(shù)據(jù)類型值的有限集合。
例如,你可能需要一個(gè)稱為“等級(jí)”,且僅可被賦值為“A”,“B”,“C”,“F”等值的類型,任何其他值在此類型中都是非法的,所以在Java5中產(chǎn)生了枚舉。
2、如何使用?
-
如下使用關(guān)鍵字enum定義了一個(gè)簡(jiǎn)單的Grade對(duì)象,使用起來(lái)和其他的Java類型一樣。
public enum Grade {A, B, C, F}; //習(xí)慣全部大寫!
-
假設(shè)有一個(gè)員工類,在員工類定義角色屬性,角色只有三個(gè)值:BOSS、MANAGER、WORKDER。
-
第一次嘗試:
class Employee { // 員工類 private String role1; public static void main(String[] args) { Employee employee = new Employee(); employee.role1 = "BOSS"; employee.role1 = "MANAGER"; employee.role1 = "MANGAER";// 非法數(shù)據(jù),但不會(huì)報(bào)錯(cuò)。如果不小心字符串拼錯(cuò)了,程序出問(wèn)題,所以直接使用String類型作為角色屬性,行不通! } }
-
第二次嘗試:
class Employee { // 員工類 private int role2; // 1 BOSS 2 MANAGE 3 WORKER public static void main(String[] args) { Employee employee = new Employee(); employee.role2 = 1; // 可讀性太差,如果角色有上十種,上百種呢? employee.role2 = 4; // 非法數(shù)據(jù),但不會(huì)報(bào)錯(cuò)。 } }
-
第三次嘗試:
class Employee { // 員工類 private int role2; // 1 BOSS 2 MANAGE 3 WORKER public static void main(String[] args) { Employee employee = new Employee(); employee.role2 = Role2.BOSS; // 相比于第二次嘗試,可讀性好了很多 employee.role2 = -1; // 非法數(shù)據(jù),但不會(huì)報(bào)錯(cuò)。 } } class Role2 { public static final int BOSS = 1; public static final int MANAGER = 2; public static final int WORKER = 3; }
-
第四次嘗試:
private Role3 role3; // 在 JDK5 之前 沒(méi)有枚舉,通過(guò)自定義類 實(shí)現(xiàn)枚舉功能 class Employee { // 員工類 private Role3 role3; // 在 JDK5 之前 沒(méi)有枚舉,通過(guò)自定義類 實(shí)現(xiàn)枚舉功能 public static void main(String[] args) { Employee employee = new Employee(); //通過(guò)自定義Role3實(shí)現(xiàn)了枚舉功能 employee.role3 = Role3.BOSS; // 可讀性好 employee.role3 = 1; // 非法數(shù)據(jù),但會(huì)報(bào)錯(cuò)! employee.role3 = new Role3(); // 非法數(shù)據(jù),但不會(huì)報(bào)錯(cuò)!檢查不出來(lái) } } class Role3 { // 枚舉功能 類 public static final Role3 BOSS = new Role3(); public static final Role3 MANAGER = new Role3(); public static final Role3 WORKER = new Role3(); private Role3() { } }
-
第五次嘗試:
class Employee { // 員工類 private Role4 role4; // 在 JDK5 之后 引入枚舉,使用枚舉表示多個(gè)角色 public static void main(String[] args) { Employee employee = new Employee(); // 使用枚舉之后 employee.role4 = Role4.MANAGER; // 可讀性良好,阻止非法數(shù)據(jù) employee.role4 = new Role4(); // 枚舉具有私有構(gòu)造方法,所以會(huì)報(bào)錯(cuò)!因此第五次嘗試優(yōu)于第四次嘗試 } } enum Role4 { // JDK5 以后引用枚舉技術(shù) 簡(jiǎn)化對(duì)象創(chuàng)建 ---- 功能等價(jià)于 Role3 BOSS, MANAGER, WORKER; }
-
3、枚舉類特性
枚舉類也是一種特殊形式的Java類。
枚舉類中聲明的每一個(gè)枚舉值代表枚舉類的一個(gè)實(shí)例對(duì)象。(可以查看.class文件,在里面明顯有每一個(gè)枚舉值的實(shí)例對(duì)象)
與Java類的普通類一樣,在聲明枚舉類的同時(shí),也可以聲明屬性、方法和構(gòu)造函數(shù),但枚舉類的構(gòu)造函數(shù)必須是私有的。(IDE中寫構(gòu)造器時(shí)會(huì)自動(dòng)生成private,刪除private也不會(huì)報(bào)錯(cuò),默認(rèn)就是private)
枚舉類也可以實(shí)現(xiàn)接口,或繼承抽象類。
Java5中擴(kuò)展了switch語(yǔ)句,它除了可以接受int、byte、chart、short外,還可以接受一
個(gè)枚舉類型。(Java7 switch 可以接受六種 : 多了一種String)若枚舉類只有一個(gè)值,則可以當(dāng)作單例設(shè)計(jì)模式使用。(見(jiàn)4、單例設(shè)計(jì)模式)
4、單例設(shè)計(jì)模式
-
單例設(shè)計(jì)模式寫法,必須包括以下三點(diǎn),因此枚舉類若只有一個(gè)值,則可以當(dāng)作單例設(shè)計(jì)模式使用。
私有構(gòu)造器
private static 成員對(duì)象
public static 獲得成員對(duì)象方法
-
懶漢式 和 餓漢式
餓漢:在創(chuàng)建對(duì)象時(shí) 直接進(jìn)行初始化
懶漢:在獲取對(duì)象時(shí) 進(jìn)行初始化
-
示例:
// 餓漢 class B { // 1、私有構(gòu)造器 private B() { } // 2、private static 對(duì)象成員 private static B b = new B(); // 3、提供public static 獲得成員方法 , 獲得唯一實(shí)例 public static B getInstance() { return b; } } // 懶漢 class C { // 1、私有構(gòu)造器 private C() { } // 2、private static 對(duì)象成員 private static C c; // 3、提供public static 獲得成員方法 , 獲得唯一實(shí)例 public static C getInstance() { if (c == null) { c = new C(); // 懶漢式 } return c; } } enum A { TEST; // 該枚舉中只有 TEST實(shí)例 ,相當(dāng)于單例設(shè)計(jì)模式! }
5、定義特殊結(jié)構(gòu)枚舉
-
在枚舉實(shí)例定義過(guò)程中
向枚舉構(gòu)造器傳入?yún)?shù)。
在枚舉中定義方法。
通過(guò)匿名內(nèi)部類實(shí)現(xiàn)枚舉中抽象方法。
-
. 示例:
public enum EnumConstructorTest {
A(10) { // 通過(guò)匿名內(nèi)部類實(shí)現(xiàn)抽象方法
@Override
public void show() {
}}, B(20) { @Override public void show() { } }; // 創(chuàng)建枚舉值時(shí),傳入構(gòu)造方法參數(shù) // 構(gòu)造方法 帶有參數(shù) private EnumConstructorTest(int a) { } // 在枚舉中定義方法 @Override public String toString() { return super.toString(); } public void print() { System.out.println("TEST"); } // 在枚舉中定義抽象方法 public abstract void show(); }
6、星期輸出中文的案例
-
加深印象:為什么要用枚舉類,如何使用枚舉類。
public class WeekDayTest { public static void main(String[] args) { WeekDay1 day1 = WeekDay1.Fri; day1.show(); WeekDay2 day2 = WeekDay2.Wed; day2.show(); } } enum WeekDay2 { Mon { @Override public void show() { System.out.println("星期一"); } }, Tue { @Override public void show() { System.out.println("星期二"); } }, Wed { @Override public void show() { System.out.println("星期三"); } }, Thu { @Override public void show() { System.out.println("星期四"); } }, Fri { @Override public void show() { System.out.println("星期五"); } }, Sat { @Override public void show() { System.out.println("星期六"); } }, Sun { @Override public void show() { System.out.println("星期日"); } }; public abstract void show(); } enum WeekDay1 { Mon, Tue, Wed, Thu, Fri, Sat, Sun; // 編寫方法 show public void show() { // 根據(jù)枚舉對(duì)象 名字 返回響應(yīng)中文星期 if (this.name().equals("Mon")) { System.out.println("星期一"); } else if (this.name().equals("Tue")) { System.out.println("星期二"); } else if (this.name().equals("Wed")) { System.out.println("星期三"); } else if (this.name().equals("Thu")) { System.out.println("星期四"); } else if (this.name().equals("Fri")) { System.out.println("星期五"); } else if (this.name().equals("Sat")) { System.out.println("星期六"); } else if (this.name().equals("Sun")) { System.out.println("星期日"); } } }
7、枚舉類API
-
Java中聲明的枚舉類,均是java.lang.Enum類的子類,它繼承了Enum類的所有方法。
常用方法:name() 返回枚舉對(duì)象名稱
ordinal() 返回枚舉對(duì)象下標(biāo)
valueOf(Class enumClass, String name) 將String類型 枚舉對(duì)象名稱 轉(zhuǎn)換為對(duì)應(yīng)的Class類型枚舉對(duì)象
-
自定義的枚舉類,在編譯階段自動(dòng)生成下面方法(即在API中沒(méi)有,在編譯后的.class文件可以找到):
valueOf(String name) 自定義枚舉類的方法,轉(zhuǎn)換枚舉對(duì)象
values() 獲得所有枚舉對(duì)象實(shí)例數(shù)組
-
五種方法示例:
public enum Color { BLUE, RED, YELLOW; // public static final Color color = new Color(); Color() {// 構(gòu)造器默認(rèn)private } } public class EnumAPITest { @Test public void demo1() { // 任何 enum 定義 枚舉類 都是默認(rèn) 繼承 Enum 類 ,使用Enum 中方法 Color color = Color.RED; // 枚舉對(duì)象 不能 new 獲得,使用已經(jīng)創(chuàng)建好對(duì)象 // name 方法返回 枚舉 實(shí)例名稱 System.out.println(color.name()); // ordinal 方法 返回 枚舉對(duì)象 下標(biāo) System.out.println(color.ordinal()); // valueOf 方法 將 String 類型 枚舉對(duì)象 名稱 ----- 轉(zhuǎn)換為相應(yīng)枚舉對(duì)象 String name = "YELLOW"; Color yellow = Enum.valueOf(Color.class, name); // 將 name 轉(zhuǎn)換 成響應(yīng)枚舉對(duì)象 System.out.println(yellow.ordinal()); // 使用枚舉類 編譯后生成兩個(gè)方法 // values 獲得 所有 枚舉對(duì)象數(shù)組 Color[] colors = Color.values(); System.out.println(Arrays.toString(colors)); // 生成valueOf 只接受String 類型枚舉名稱,將名稱轉(zhuǎn)換為當(dāng)前枚舉類對(duì)象 String name2 = "BLUE"; Color blue = Color.valueOf(name2); // 將name2 枚舉對(duì)象名稱 轉(zhuǎn)換 Color對(duì)象枚舉實(shí)例 System.out.println(blue.ordinal()); } }
-
枚舉對(duì)象、枚舉對(duì)象下標(biāo)、枚舉對(duì)象名,三者之間的相互轉(zhuǎn)換(用上五種方法,必須掌握!):
@Test // 枚舉對(duì)象、枚舉對(duì)象下標(biāo)、枚舉對(duì)象名稱表示之間的轉(zhuǎn)換 public void demo2() { // 第一種 已知枚舉對(duì)象 --- 獲得下標(biāo)和名稱 Color blue = Color.BLUE; // 獲得下標(biāo) System.out.println(blue.ordinal()); // 獲得名稱 System.out.println(blue.name()); System.out.println("----------------------------------"); // 第二種 已知枚舉對(duì)象 下標(biāo) --- 獲得枚舉對(duì)象實(shí)例 和 名稱 int index = 1; // 獲得枚舉對(duì)象 Color red = Color.values()[index]; // 獲得名稱 System.out.println(red.name()); System.out.println("---------------------------------"); // 第三種 已知枚舉對(duì)象名稱 ----- 獲得枚舉對(duì)象實(shí)錄 和 下標(biāo) String name = "YELLOW"; // 獲得實(shí)例 Color c1 = Enum.valueOf(Color.class, name); Color c2 = Color.valueOf(name); // 獲得下標(biāo) System.out.println(c1.ordinal()); System.out.println(c2.ordinal()); }
參考閱讀:
《Effective Java 中文版 第2版》chapter 6
《JAVA 5.0 TIGER程序高手秘籍》chapter 3