日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java.lang包—枚举类Enum

發(fā)布時間:2024/4/15 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java.lang包—枚举类Enum 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

原文作者:山高我為

原文地址:java enum的用法詳解

目錄

一、enum關(guān)鍵字

二、Enum類源碼

三、疑問

四、Enum常見用法


一、enum關(guān)鍵字

enum關(guān)鍵字是在Java1.5也就是Java SE5之后引入的一個新特性:它通過關(guān)鍵字enum來定義一個枚舉類,這個被定義的枚舉類繼承Enum類,這個枚舉類算是一種特殊類,它同樣能像其他普通類一樣擁有構(gòu)造器、方法,也能夠?qū)崿F(xiàn)接口,但是它不能再繼承其他別的類,因為它的直接父類是Enum類,并且因為它默認的修飾符有final的存在,因此它無法直接派生出其他子類,除非將其使用abstract修飾。

按照《Java編程思想》中的原話來說:關(guān)鍵字enum可以將一組具名的值的有限集合創(chuàng)建為一種新的類型,而這些具名的值可以作為常規(guī)的程序組件來使用。

在枚舉類出現(xiàn)之前Java是將常量放在接口或是放在普通類當中,然后使用public、static、final去修飾定義的常量,如下兩個例子:

public interface Constants2 {public static final int CONSTANT_1 = 1;public static final int CONSTANT_2 = 2;public static final int CONSTANT_3 = 3; }public class Constants {public static final int CONSTANT_1 = 1;public static final int CONSTANT_2 = 2;public static final int CONSTANT_3 = 3; }

在枚舉類型出現(xiàn)之后,就可以使用枚舉類型來定義常量,這些枚舉類型成員_1、_2、_3都默認被public、static、final修飾,語法如下:

public enum Constants {CONSTANT_1,CONSTANT_2,CONSTANT_3 }

?

但是Java枚舉類型輸出其常量的時候不像C?/C++的枚舉那樣是數(shù)字,輸出的是其常量名,如果需要輸出其類型成員聲明時數(shù)字次序的話,需要調(diào)用ordinal()方法:

public enum Singleton2 {SHERLOCK,WASTON; }class Main{public static void main(String[] args) {System.out.println(Singleton2.SHERLOCK);System.out.println(Singleton2.WASTON);System.out.println(Singleton2.SHERLOCK.ordinal());System.out.println(Singleton2.WASTON.ordinal());} }//輸出結(jié)果: //SHERLOCK //WASTON //0 //1

?

二、Enum類源碼

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {/*** 枚舉常量的名稱* 使用toString方法訪問此字段。*/private final String name;/*** 返回此枚舉常量的名稱,與其枚舉聲明中聲明的完全相同.* 大多數(shù)程序員應(yīng)優(yōu)先使用toString方法,因為toString方法可能會返回一個更加友好的名稱。* 此方法主要用于特殊情況,其中正確性取決于獲取確切名稱,不會因發(fā)行版本而異。*/public final String name() {return name;}/*** 枚舉常量的序數(shù)(它指的是在枚舉聲明中的位置,其中初始常量的序數(shù)為零)。* 大多數(shù)程序員都不會使用這個字段。 它設(shè)計用于復(fù)雜的基于枚舉型的數(shù)據(jù)結(jié)構(gòu),例如EnumSet,EnumMap。*/private final int ordinal;/*** 返回枚舉常量的序數(shù)*/public final int ordinal() {return ordinal;}/*** 唯一的構(gòu)造函數(shù)。 程序員無法調(diào)用此構(gòu)造函數(shù)。它由編譯器發(fā)出的代碼用于響應(yīng)枚舉類型聲明*/protected Enum(String name, int ordinal) {this.name = name;this.ordinal = ordinal;}/*** 返回枚舉常量的名稱。雖然沒有覆蓋的必要性,但該方法允許進行覆蓋。* 當存在需要更“友好”的字符串形式時,枚舉類型類應(yīng)該重寫此方法。*/public String toString() {return name;}/*** 如果指定的對象等于此枚舉常量,則返回true。* 【注意】此處比較形式是通過“==”進行,也即是枚舉類之間可以通過 == 進行比較*/public final boolean equals(Object other) {return this==other;}/*** 返回此枚舉常量的哈希碼*/public final int hashCode() {return super.hashCode();}/*** 拋出CloneNotSupportedException異常. * 這能保證了枚舉常量類永遠不會被克隆,從而保證其為”單例”狀態(tài)。*/protected final Object clone() throws CloneNotSupportedException {throw new CloneNotSupportedException();}/*** 將此枚舉與指定的對象進行比較以進行排序. * 返回一個負整數(shù),零或正整數(shù),因為此對象小于,等于或大于指定的對象,枚舉常量只能與其他具有相同枚舉類型的枚舉常量相相比較.* 此方法實現(xiàn)的自然順序是聲明常量的順序*/public final int compareTo(E o) {Enum<?> other = (Enum<?>)o;Enum<E> self = this;if (self.getClass() != other.getClass() && // optimizationself.getDeclaringClass() != other.getDeclaringClass())throw new ClassCastException();return self.ordinal - other.ordinal;}/*** 返回與此枚舉常量的枚舉類型對應(yīng)的Class對象. * 當且僅當e1.getDeclaringClass()== e2.getDeclaringClass()時, 兩個枚舉常量e1和e2屬于相同的枚舉類型。*/@SuppressWarnings("unchecked")public final Class<E> getDeclaringClass() {Class<?> clazz = getClass();Class<?> zuper = clazz.getSuperclass();return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;}/*** 返回指定枚舉類型的枚舉常量指定的名稱. * 名稱必須與聲明此類型的枚舉常量使用的標識符完全匹配(不允許使用無關(guān)的空格字符.)* 請注意,對于特定的枚舉類型T,可以使用該枚舉上隱式聲明的valueOf(String)方法代替此方法從名稱映射到相應(yīng)的枚舉常量。 * 枚舉類型的所有常量都可以通過調(diào)用該類型的隱式方法 values()方法來獲得。** @param <T> 返回常量的枚舉類型* @param 枚舉常量類型enumType* @param 要返回的枚舉常量的名稱name* @return 返回具有指定名稱和指定枚舉類型的枚舉常量* @throws 如果指定的枚舉類型沒有具有指定名稱的常量,或者指定的類對象不表示枚舉類型,拋出IllegalArgumentException 異常* @throws 如果enumType或者code name為null,NullPointerException異常*/public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name) {T result = enumType.enumConstantDirectory().get(name);if (result != null)return result;if (name == null)throw new NullPointerException("Name is null");throw new IllegalArgumentException("No enum constant " + enumType.getCanonicalName() + "." + name);}/*** 枚舉類不能有finalize方法*/protected final void finalize() { }/*** 無法反序列化枚舉*/private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException {throw new InvalidObjectException("can't deserialize enum");}private void readObjectNoData() throws ObjectStreamException {throw new InvalidObjectException("can't deserialize enum");} }

三、疑問

1、為什么說enum本質(zhì)是一個繼承了Enum類的class?

Java語法就是這么規(guī)定的,還能為啥

2、枚舉聲明為什么是enum不是class,這樣做的意圖是什么?

3、枚舉允許繼承類嗎?可以被別人結(jié)成么?

枚舉不允許繼承類。Jvm在生成枚舉時已經(jīng)繼承了Enum類,由于Java語言是單繼承,不支持再繼承額外的類(唯一的繼承名額被Jvm用了)。也不可以繼承枚舉。因為Jvm在生成枚舉類時,將它聲明為final。

4、枚舉可以用等號比較嗎?

枚舉可以用等號比較。Jvm會為每個枚舉實例對應(yīng)生成一個類對象,這個類對象是用public static final修飾的,在static代碼塊中初始化,是一個單例。

5、為什么使用枚舉代替常量類?

在我們平常的開發(fā)中,為表示同種類型的不同種類,經(jīng)常的做法是聲明一組具名的int常量來表示,每個類型成員一個常量,如:

public static final int DAY_MONDAY = 1; public static final int DAY_TUESDAY = 2; public static final int DAY_WEDNESDAY = 3; public static final int DAY_THURSDAY = 4; public static final int DAY_FRIDAY = 5; public static final int DAY_SATURDAY = 6; public static final int DAY_SUNDAY = 7;public static final int ORANGE_NAVEL = 0; public static final int ORANGE_TEMPLE = 1; public static final int ORANGE_BLOOD = 2;

這種方法稱做?int枚舉模式,這種方式在安全性和使用方便性方面沒有任何幫助。

a、將day傳到想要orange的方法中,編譯器不會警告,執(zhí)行也不會出現(xiàn)錯誤;
b、用==操作符將day與orange比較,編譯器不會警告,執(zhí)行也不會出現(xiàn)錯誤;
c、int枚舉是編譯時常量,被編譯到客戶端中,如果枚舉常量關(guān)聯(lián)的int發(fā)生變化,客戶端必須重新編譯,如果沒有重新編譯,程序仍可以運行,但行為就確定了,如DAY_MONDAY關(guān)聯(lián)的常量不再是1,而是0。
d、將int枚舉常量翻譯成可打印的字符串很麻煩
e、如果想要遍歷一個組中的所有int 枚舉常量,甚至獲得int枚舉組的大小,這種實現(xiàn)沒有啥方便可靠的方法。

因此,推薦使用枚舉類型來代替這種int枚舉常量:

public enum DAY {DAY_MONDAY, DAY_TUESDAY, DAY_WEDNESDAY,DAY_THURSDAY, DAY_FRIDAY, DAY_SATURDAY, DAY_SUNDAY}public enum ORANGE {ORANGE_NAVEL, ORANGE_TEMPLE, ORANGE_BLOOD}

這種枚舉類型,提供了編譯時的類型安全檢查,如果聲明了一個參數(shù)的類型為DAY,就可以保證,被傳到該參數(shù)上的任何非null的對象引用一定屬于其他有效值中的一個,試圖傳遞類型錯誤的值時,會導(dǎo)致編譯時錯誤,就像試圖將某種枚舉類型的表達式賦給另一種枚舉類型的變量,或者試圖利用==操作符比較不同枚舉類型的值一樣。同時包含同名常量的多個枚舉類型可以共存,因為每個類型有自己的命名空間,增加或重新排列枚舉類型的常量,無需重新編譯客戶端的代碼。如果想獲取類型對應(yīng)的字符串,直接通過toString方法即可。

枚舉類型除了完善了int枚舉模式的不足之處外,枚舉類型還允許添加任意的方法和域,并實現(xiàn)任意的接口。這個有什么用途呢?

a、能夠?qū)?shù)據(jù)與它的常量關(guān)聯(lián)起來,例如能夠返回水果顏色或者水果圖片的方法,對于我們的ORANGE類型來說可能就很有好處;
b、你可使用適當?shù)姆椒▉碓鰪娒杜e類型,枚舉類型可以先作為枚舉常量的一個簡單集合,隨著時間的推移在演變成為全功能的抽象。

另外,當你想要每增加一種枚舉常量時,需要強制選擇一種對應(yīng)的策略,可以使用枚舉提供的策略枚舉(strategy enum)?的方式。

4、究竟是枚舉的性能好,還是常量類好?

5、為什么枚舉要實現(xiàn)Comparable接口?

6、為什么枚舉要實現(xiàn)Serializable接口?

7、為什么枚舉支持泛型?

8、枚舉的底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組還是鏈表?

9、為什么枚舉類型實例化就能訪?比如如下代碼為什么不報錯

public class Traffic{public enum Light{GREEN,YELLOW,RED} } Traffic.Light state = Traffic.Light.GREEN;

Java枚舉類型都是靜態(tài)常量,隱式的用static final修飾過。確切的說,Java枚舉類型是“靜態(tài)常量”,這里面包含了兩層意思:

  • 枚舉型中的實例隱式地用static final修飾過。
  • 枚舉型作為某個類中的成員字段也隱式的用static final修飾過

還是你上面這個代碼,反編譯一下,你就能看到--編譯器背著你偷偷做了哪些手腳

  • 首先,枚舉型Light是個實實在在的類。集成自基類Enum<Light>。然后在你不知情的情況下,偷偷加了static final修飾詞。然后3個枚舉實例?GREEN,YELLOW,RED也確確實實是light的實例,然后前面加了static final。
  • 然后構(gòu)造器也被偷偷的閹割成private。這種實例控制手段,是不是在單例模式里面見過,所以枚舉也是實現(xiàn)單例器的一種方法。
  • 然后編譯器還偷偷的告訴Light[]數(shù)組,一個values()方法,一個valueO()f方法,這個values在Enum文檔里面找不到,如果在Enum里面定義一個相關(guān)方法,你還會看到一個匿名內(nèi)部類

反編譯的結(jié)果如下:

總之,Java的Enum枚舉類型就是一個大大的“語法糖”。明明是一個完整的類,但只向用戶暴露幾個常態(tài)變量,隱藏掉大部分實現(xiàn)細節(jié)。

上述文字引用自知乎問答:Java 枚舉型為什么是靜態(tài)的,以及是怎么實現(xiàn)的?胖君的回答

10、是不是所有的枚舉都默認是靜態(tài)的?

通過可問題5,可知所有的枚舉都默認是靜態(tài)的

?

11、枚舉有哪些應(yīng)用場景?

12、枚舉是如何實現(xiàn)單例的?

public enum Singleton2 {SHERLOCK }class Main{public static void main(String[] args) {Singleton2 sherlock = Singleton2.SHERLOCK;Singleton2 sherlock1 = Singleton2.SHERLOCK;System.out.println(sherlock == Singleton2.SHERLOCK);System.out.println(sherlock == sherlock1);System.out.println(Singleton2.SHERLOCK.getDeclaringClass());} }輸出結(jié)果: true true class com.sherlock.singleton.Singleton2

四、Enum常見用法

用法一:常量

在JDK1.5 之前,我們定義常量都是: public static fianl.... ?,F(xiàn)在好了,有了枚舉,可以把相關(guān)的常量分組到一個枚舉類型里,而且枚舉提供了比常量更多的方法。

public enum Color { RED, GREEN, BLANK, YELLOW }

用法二:switch

JDK1.6之前的switch語句只支持int,char,enum類型,使用枚舉,能讓我們的代碼可讀性更強。

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 實例。

?

public enum Color {RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);// 成員變量private String name;private int index;// 構(gòu)造方法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()方法覆蓋的例子。

public class Test {public enum Color {RED("紅色", 1), GREEN("綠色", 2), BLANK("白色", 3), YELLO("黃色", 4);// 成員變量private String name;private int index;// 構(gòu)造方法private Color(String name, int index) {this.name = name;this.index = index;}// 覆蓋方法@Overridepublic String toString() {return this.index + "_" + this.name;}}public static void main(String[] args) {System.out.println(Color.RED.toString());} }

用法五:實現(xiàn)接口

所有的枚舉都繼承自java.lang.Enum類。由于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;// 構(gòu)造方法private Color(String name, int index) {this.name = name;this.index = index;}// 接口方法@Overridepublic String getInfo() {return this.name;}// 接口方法@Overridepublic void print() {System.out.println(this.index + ":" + this.name);} }

?

用法六:使用接口組織枚舉?

?

public interface Food {enum Coffee implements Food {BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO}enum Dessert implements Food {FRUIT, CAKE, GELATO} }

?

用法七:關(guān)于枚舉集合的使用

java.util.EnumSet和java.util.EnumMap是兩個枚舉集合。EnumSet保證集合中的元素不重復(fù);EnumMap中的 key是enum類型,而value則可以是任意類型。關(guān)于這個兩個集合的使用就不在這里贅述,可以參考JDK文檔。?完整示例代碼

枚舉類型的完整演示代碼如下:

?

public class LightTest {// 1.定義枚舉類型public enum Light {// 利用構(gòu)造函數(shù)傳參RED(1), GREEN(3), YELLOW(2);// 定義私有變量private int nCode;// 構(gòu)造函數(shù),枚舉類型只能為私有private Light(int _nCode) {this.nCode = _nCode;}@Overridepublic String toString() {return String.valueOf(this.nCode);}}public static void main(String[] args) {// 1.遍歷枚舉類型System.out.println("演示枚舉類型的遍歷 ......");testTraversalEnum();// 2.演示EnumMap對象的使用System.out.println("演示EnmuMap對象的使用和遍歷.....");testEnumMap();// 3.演示EnmuSet的使用System.out.println("演示EnmuSet對象的使用和遍歷.....");testEnumSet();}/*** * 演示枚舉類型的遍歷*/private static void testTraversalEnum() {Light[] allLight = Light.values();for (Light aLight : allLight) {System.out.println("當前燈name:" + aLight.name());System.out.println("當前燈ordinal:" + aLight.ordinal());System.out.println("當前燈:" + aLight);}}/*** * 演示EnumMap的使用,EnumMap跟HashMap的使用差不多,只不過key要是枚舉類型*/private static void testEnumMap() {// 1.演示定義EnumMap對象,EnumMap對象的構(gòu)造函數(shù)需要參數(shù)傳入,默認是key的類的類型EnumMap<Light, String> currEnumMap = new EnumMap<Light, String>(Light.class);currEnumMap.put(Light.RED, "紅燈");currEnumMap.put(Light.GREEN, "綠燈");currEnumMap.put(Light.YELLOW, "黃燈");// 2.遍歷對象for (Light aLight : Light.values()) {System.out.println("[key=" + aLight.name() + ",value="+ currEnumMap.get(aLight) + "]");}}/*** * 演示EnumSet如何使用,EnumSet是一個抽象類,獲取一個類型的枚舉類型內(nèi)容<BR/>* * 可以使用allOf方法*/private static void testEnumSet() {EnumSet<Light> currEnumSet = EnumSet.allOf(Light.class);for (Light aLightSetElement : currEnumSet) {System.out.println("當前EnumSet中數(shù)據(jù)為:" + aLightSetElement);}} }

?

執(zhí)行結(jié)果如下:

演示枚舉類型的遍歷 ...... 當前燈name:RED 當前燈ordinal:0 當前燈:1 當前燈name:GREEN 當前燈ordinal:1 當前燈:3 當前燈name:YELLOW 當前燈ordinal:2 當前燈:2 演示EnmuMap對象的使用和遍歷..... [key=RED,value=紅燈] [key=GREEN,value=綠燈] [key=YELLOW,value=黃燈] 演示EnmuSet對象的使用和遍歷..... 當前EnumSet中數(shù)據(jù)為:1 當前EnumSet中數(shù)據(jù)為:3 當前EnumSet中數(shù)據(jù)為:2

讀后有收獲可以支付寶請作者喝奶茶?

?

總結(jié)

以上是生活随笔為你收集整理的java.lang包—枚举类Enum的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。