這篇文章主要講解了“Java中的枚舉相關(guān)知識點總結(jié)”,文中的講解內(nèi)容簡單清晰,易于學(xué)習(xí)與理解,下面請大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java中的枚舉相關(guān)知識點總結(jié)”吧!
創(chuàng)新互聯(lián)擁有一支富有激情的企業(yè)網(wǎng)站制作團隊,在互聯(lián)網(wǎng)網(wǎng)站建設(shè)行業(yè)深耕10余年,專業(yè)且經(jīng)驗豐富。10余年網(wǎng)站優(yōu)化營銷經(jīng)驗,我們已為近1000家中小企業(yè)提供了成都網(wǎng)站設(shè)計、成都做網(wǎng)站解決方案,定制網(wǎng)站,設(shè)計滿意,售后服務(wù)無憂。所有客戶皆提供一年免費網(wǎng)站維護!
Java中的枚舉
枚舉通常是一組相關(guān)的常量集合,其他編程語言很早就開始用枚舉了,比如C++。從JDK1.5起,Java也開始支持枚舉類型。
枚舉是一種特殊的數(shù)據(jù)類型,它既是一種類(class)類型卻又比類類型多了些特殊的約束,這些約束也造就了枚舉類型的簡潔性、安全性以及便捷性。
在Java中,通過enum來聲明枚舉類型,默認繼承自java.lang.Enum。所以聲明枚舉類時無法再繼承其他類。
枚舉聲明
在生活中我們會經(jīng)常辨認方向,東南西北,它們的名稱、屬性等基本都是確定的,我們就可以將其聲明為枚舉類型:
public enum Direction { EAST, WEST, NORTH, SOUTH; }
同樣,每周七天也可以聲明成枚舉類型:
enum Day { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY }
在沒有枚舉或沒使用枚舉的情況下,并不是說不可以定義變量,我們可以通過類或接口進行常量的定義:
public class Day { public static final int MONDAY =1; public static final int TUESDAY=2; public static final int WEDNESDAY=3; public static final int THURSDAY=4; public static final int FRIDAY=5; public static final int SATURDAY=6; public static final int SUNDAY=7; }
但這樣存在許多不足,如在類型安全和使用方便性上。如果存在定義int值相同的變量,混淆的幾率還是很大的,編譯器也不會提出任何警告。因此,當能使用枚舉的時候,并不提倡這種寫法。
枚舉的底層實現(xiàn)
上面我們已經(jīng)說了,枚舉是一個特殊的類,每一個枚舉項本質(zhì)上都是枚舉類自身的實例。
因此,上面枚舉類Direction可以通過下面代碼進行示例:
final class Direction extends Enum{ public final static Direction EAST = new Direction(); public final static Direction WEST = new Direction(); public final static Direction NORTH = new Direction(); public final static Direction SOUTH = new Direction(); }
首先通過javac命令對Direction進行編譯,然后通過javap命令來查看一下對應(yīng)class文件內(nèi)容:
bogon:enums apple$ javap Direction.class Compiled from "Direction.java" public final class com.choupangxia.enums.Direction extends java.lang.Enum{ public static final com.choupangxia.enums.Direction EAST; public static final com.choupangxia.enums.Direction WEST; public static final com.choupangxia.enums.Direction NORTH; public static final com.choupangxia.enums.Direction SOUTH; public static com.choupangxia.enums.Direction[] values(); public static com.choupangxia.enums.Direction valueOf(java.lang.String); static {}; }
可以看到,一個枚舉在經(jīng)過編譯器編譯過后,變成了一個抽象類,它繼承了java.lang.Enum;而枚舉中定義的枚舉常量,變成了相應(yīng)的public static final屬性,而且其類型就抽象類的類型,名字就是枚舉常量的名字。
枚舉使用實例
通過上面的反編譯我們可以看到,枚舉的選項本質(zhì)上就是public static final的變量,所以就把它當做這樣的變量使用即可。
public class EnumExample { public static void main(String[] args) { Direction north = Direction.NORTH; System.out.println(north); //Prints NORTH } }
枚舉的ordinal()方法
ordinal()方法用于獲取枚舉變量在枚舉類中聲明的順序,下標從0開始,與數(shù)組中的下標很相似。它的設(shè)計是用于EumSet和EnumMap復(fù)雜的基于枚舉的數(shù)據(jù)結(jié)構(gòu)使用。
Direction.EAST.ordinal(); //0 Direction.NORTH.ordinal(); //2
需要注意的是如果枚舉項聲明的位置發(fā)生了變化,那么ordinal方法的值也隨之變化。所以,進來避免使用該方法。不然,當枚舉項比較多時,別人在中間增刪一項,會導(dǎo)致后續(xù)的所有順序變化。
枚舉的values()和valueOf()
values()方法可獲取枚舉類中的所有變量,并作為數(shù)組返回:
Direction[] directions = Direction.values(); for (Direction d : directions) { System.out.println(d); } //Output: EAST WEST NORTH SOUTH
values()方法是由編譯器插入到枚舉類中的static方法,而它的父類Enum中并不存在這個方法。
valueOf(String name)方法與Enum類中的valueOf方法的作用類似根據(jù)名稱獲取枚舉變量,同樣是由編譯器生成的,但更簡潔些,只需傳遞一個參數(shù)。
Direction east = Direction.valueOf("EAST"); System.out.println(east); //Output: EAST
枚舉命名約定
按照約定,枚舉屬于常量,因此采用所有字母大寫,下劃線分割的風格(UPPER_CASE)。也就是說枚舉類名與普通類約定一樣,而枚舉中的變量與靜態(tài)變量的命名規(guī)范一致。
枚舉的構(gòu)造方法
默認情況下,枚舉類是不需要構(gòu)造方法的,默認的變量就是聲明時的字符串。當然,你也可以通過自定義構(gòu)造方法,來初始化枚舉的一些狀態(tài)信息。通常情況下,我們會在構(gòu)造參數(shù)中傳入兩個參數(shù),比如,一個編碼,一個描述。
以上面的方向為例:
public enum Direction { // enum fields EAST(0), WEST(180), NORTH(90), SOUTH(270); // constructor private Direction(final int angle) { this.angle = angle; } // internal state private int angle; public int getAngle() { return angle; } }
如果我們想訪問每個方向的角度,可以通過簡單的方法調(diào)用:
Direction north = Direction.NORTH; System.out.println(north); //NORTH System.out.println(north.getAngle()); //90 System.out.println(Direction.NORTH.getAngle()); //90
枚舉中的方法
枚舉就是一個特殊的類,因此也可以像普通的類一樣擁有方法和屬性。在枚舉中不僅可以聲明具體的方法,還可以聲明抽象方法。
方法的訪問權(quán)限可以是private、protected和public??梢酝ㄟ^這些方法返回枚舉項的值,也可以做一些內(nèi)部的私有處理。
public enum Direction { // enum fields EAST, WEST, NORTH, SOUTH; protected String printDirection() { String message = "You are moving in " + this + " direction"; System.out.println( message ); return message; } }
對應(yīng)方法的使用如下:
Direction.NORTH.printDirection(); Direction.EAST.printDirection();
枚舉類中還可以定義抽象的方法,但每個枚舉項中必須實現(xiàn)對應(yīng)的抽象方法:
public enum Direction { // enum fields EAST { @Override public String printDirection() { String message = "You are moving in east. You will face sun in morning time."; return message; } }, WEST { @Override public String printDirection() { String message = "You are moving in west. You will face sun in evening time."; return message; } }, NORTH { @Override public String printDirection() { String message = "You are moving in north. You will face head in daytime."; return message; } }, SOUTH { @Override public String printDirection() { String message = "You are moving in south. Sea ahead."; return message; } }; public abstract String printDirection(); }
抽象方法的調(diào)用,與普通方法一樣:
Direction.NORTH.printDirection(); Direction.EAST.printDirection();
通過這種方式就可以輕而易舉地定義每個枚舉實例的不同行為方式。比如需要每個枚舉項都打印出方向的名稱,就可以定義這么一個抽象的方法。
上面的實例enum類似乎表現(xiàn)出了多態(tài)的特性,可惜的是枚舉類型的實例終究不能作為類型傳遞使用。下面的方式編譯器都無法通過:
//無法通過編譯,Direction.NORTH是個實例對象 public void text(Direction.NORTH instance){ }
枚舉的繼承
上面已經(jīng)提到過枚舉繼承自java.lang.Enum,Enum是一個抽象類:
public abstract class Enum> implements Comparable , Serializable { // ... }
也就是說,所有的枚舉類都支持比較(Comparable)和序列化(Serializable)的特性。也正因為所有的枚舉類都繼承了Enum,所以無法再繼承其他類了,但是可以實現(xiàn)接口。
枚舉的比較
所有的枚舉默認都是Comparable和單例的,因此可以通過equals方法進行比較,甚至可以直接用雙等號“==”進行比較。
Direction east = Direction.EAST; Direction eastNew = Direction.valueOf("EAST"); System.out.println( east == eastNew ); //true System.out.println( east.equals( eastNew ) ); //true
枚舉集合:EnumSet和EnumMap
在java.util包下引入了兩個枚舉集合類:EnumSet和EnumMap。
EnumSet
EnumSet類的定義如下:
public abstract class EnumSet> extends AbstractSet implements Cloneable, java.io.Serializable{ // ... }
EnumSet是與枚舉類型一起使用的專用Set集合,EnumSet中所有元素都必須是枚舉類型。與其他Set接口的實現(xiàn)類HashSet/TreeSet不同的是,EnumSet在內(nèi)部實現(xiàn)是位向量。
位向量是一種極為高效的位運算操作,由于直接存儲和操作都是bit,因此EnumSet空間和時間性能都十分可觀,足以媲美傳統(tǒng)上基于int的“位標志”的運算,關(guān)鍵是我們可像操作set集合一般來操作位運算。
EnumSet不允許使用null元素,試圖插入null將拋出 NullPointerException,但測試判斷是否存在null元素或移除null元素則不會拋出異常,與大多數(shù)Collection實現(xiàn)一樣,EnumSet不是線程安全的,在多線程環(huán)境下需注意數(shù)據(jù)同步問題。
使用實例:
public class Test { public static void main(String[] args) { Set enumSet = EnumSet.of( Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH ); } }
EnumMap
EnumMap的聲明如下:
public class EnumMap, V> extends AbstractMap implements java.io.Serializable, Cloneable {}
與EnumSet類似,EnumMap是一個特殊的Map,Map的Key必須是枚舉類型。EnumMap內(nèi)部是通過數(shù)組實現(xiàn)的,效率比普通的Map更高一些。EnumMap的key值不能為null,并且EnumMap也不是線程安全的。
EnumMap使用實例如下:
public class Test { public static void main(String[] args){ //Keys can be only of type Direction Map enumMap = new EnumMap(Direction.class); //Populate the Map enumMap.put(Direction.EAST, Direction.EAST.getAngle()); enumMap.put(Direction.WEST, Direction.WEST.getAngle()); enumMap.put(Direction.NORTH, Direction.NORTH.getAngle()); enumMap.put(Direction.SOUTH, Direction.SOUTH.getAngle()); } }
枚舉與switch
使用switch進行條件判斷時,條件參數(shù)一般只能是整型,字符型,同時也支持枚舉型,在java7后switch也對字符串進行了支持。
使用實例如下:
enum Color {GREEN,RED,BLUE} public class EnumDemo4 { public static void printName(Color color){ switch (color){ //無需使用Color進行引用 case BLUE: System.out.println("藍色"); break; case RED: System.out.println("紅色"); break; case GREEN: System.out.println("綠色"); break; } } public static void main(String[] args){ printName(Color.BLUE); printName(Color.RED); printName(Color.GREEN); } }
枚舉與單例
單例模式是日常使用中最常見的設(shè)計模式之一了,單例的實現(xiàn)有很多種實現(xiàn)方法(餓漢模式、懶漢模式等),這里就不再贅述,只以一個最普通的單例來做對照,進而看看基于枚舉如何來實現(xiàn)單例模式。
餓漢模式的實現(xiàn):
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance() { return instance; } }
簡單直接,缺點是可能在還不需要時就把實例創(chuàng)建出來了,沒起到lazy loading的效果。優(yōu)點就是實現(xiàn)簡單,而且安全可靠。
這樣一個單例場景,如果通過枚舉進行實現(xiàn)如下:
public enum Singleton { INSTANCE; public void doSomething() { System.out.println("doSomething"); } }
在effective java中說道,最佳的單例實現(xiàn)模式就是枚舉模式。利用枚舉的特性,讓JVM來幫我們保證線程安全和單一實例的問題。除此之外,寫法還特別簡單。
直接通過Singleton.INSTANCE.doSomething()的方式調(diào)用即可。方便、簡潔又安全。
感謝各位的閱讀,以上就是“Java中的枚舉相關(guān)知識點總結(jié)”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對Java中的枚舉相關(guān)知識點總結(jié)這一問題有了更深刻的體會,具體使用情況還需要大家實踐驗證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識點的文章,歡迎關(guān)注!