首頁(yè)常見(jiàn)問(wèn)題正文

java中枚舉類(lèi)型enum用法及其背后原理

更新時(shí)間:2023-02-15 來(lái)源:黑馬程序員 瀏覽量:

IT培訓(xùn)班

Enum枚舉類(lèi)型

Enum的全寫(xiě)是Enumeration,這個(gè)詞的翻譯是列舉、逐條陳述、細(xì)目。在程序語(yǔ)言中,枚舉類(lèi)型是一種特殊的數(shù)據(jù)類(lèi)型(常用的數(shù)據(jù)類(lèi)型比如字符串、整型),這種數(shù)據(jù)類(lèi)型的變量值限定在固定的范圍, 比如季節(jié)只有春夏秋冬,月份是12個(gè)。

Java中的枚舉

枚舉前時(shí)代

在Java語(yǔ)言中, 枚舉類(lèi)型從JDK1.5才開(kāi)始提供。在這之前使用接口靜態(tài)常量來(lái)實(shí)現(xiàn)相關(guān)功能(也可以是類(lèi)靜態(tài)常量),以季節(jié)為例:

在不使用枚舉類(lèi)之前,一般使用接口靜態(tài)常量實(shí)現(xiàn)。比如:

public interface Season {
    public static final int SPRING = 1;
    public static final int SUMMER = 2;
    public static final int AUTUMN = 3;
    public static final int WINTER = 4;
}

使用JUnit使用測(cè)試如下:

@Test
public void noEnum() {
  int i = 1;
  Assert.assertTrue(Season.SPRING==i);
}


使用接口靜態(tài)常量的方式比較難限定變量的范圍,而且定義繁瑣,功能也很有限,于是在Java 1.5 中定義了一個(gè)枚舉類(lèi)型:java.lang.Enum。

Java枚舉的定義

類(lèi)似類(lèi)(class)和接口(interface)的定義,Java提供enum關(guān)鍵字用來(lái)定義枚舉類(lèi),在IDEA中創(chuàng)建枚舉類(lèi)的菜單如下:

1603951100204_枚舉0.jpg


同樣定義一個(gè)季節(jié)的枚舉類(lèi), 代碼可以簡(jiǎn)潔如下:

package cn.osxm.jcodef.func.base;
public enum SeasonEnum {
    SPRING, SUMMER, AUTUMN, WINTER
}

在枚舉類(lèi)中直接列出常量,常量遵循全部大寫(xiě)的規(guī)則。在上面的枚舉類(lèi)示例代碼中,SPRING, SUMMER, AUTUMN, WINTER 是SeasonEnum的成員。

枚舉成員默認(rèn)是final、public、static (所以可以使用SeasonEnum.SPRING方式調(diào)用枚舉成員)

每一個(gè)枚舉類(lèi)型成員都可以看作是枚舉類(lèi)的實(shí)例 (SeasonEnum.SPRING的類(lèi)型也是SeasonEnum)

在JUnit使用測(cè)試如下:

@Test
public void enumBase() {
    SeasonEnum season = SeasonEnum.SPRING;
    Assert.assertTrue(season.equals(SeasonEnum.SPRING));
}


Java 枚舉類(lèi)的特性

Java枚舉類(lèi)的特性有:

枚舉可以實(shí)現(xiàn)接口,但不能繼承接口,也不能被繼承。

枚舉類(lèi)是final的,所以不能繼承。

枚舉類(lèi)的構(gòu)造方法是私有的

枚舉成員是靜態(tài)、final和public

枚舉成員是枚舉類(lèi)的實(shí)例

但是從上面SeasonEnum枚舉類(lèi)的定義來(lái)看,完全看不出這些特性,這些特性是怎么來(lái)的呢? 請(qǐng)看下面的原理探求。

Java枚舉類(lèi)實(shí)現(xiàn)的原理探求

Java枚舉類(lèi)型的奧秘就在編譯階段,枚舉類(lèi)在編譯后會(huì)生成了一個(gè)擴(kuò)展java.lang.Enum的類(lèi)。這個(gè)可以通過(guò)JDK自帶的javap工具來(lái)反編譯生成的.class文件。對(duì)上面的生成的SeasonEnum.class文件進(jìn)行反編譯,因?yàn)檫@個(gè)文件的包路徑是cn\osxm\jcodef\func\base,所以在命令行使用如下命令:

javap -p cn\osxm\jcodef\func\base\SeasonEnum.class


·-p參數(shù)的意思是反編譯代碼中包含私有的方法, p是private的意思。

1603951118430_枚舉1.jpg


從控制臺(tái)輸出的反編譯后的源碼可以看出:

·自定義的枚舉類(lèi)會(huì)自動(dòng)繼承java.lang.Enum類(lèi)

·每個(gè)成員變量都會(huì)被轉(zhuǎn)換為 private static final的枚舉類(lèi)型的實(shí)例

·自動(dòng)添加private的構(gòu)造函數(shù) 從反編譯后的源碼就不難理解Enum的特性了。

注意: 使用專門(mén)的Java反編譯工具,比如JD GUI、luyten等對(duì)Eumn進(jìn)行反編譯的效果接近源碼的效果,無(wú)法看到繼承等特性,JD-GUI反編譯的效果和源碼時(shí)一致的,這也說(shuō)明使用JD GUI來(lái)進(jìn)行實(shí)際的反編譯還是不錯(cuò)的。

分享到:
在線咨詢 我要報(bào)名
和我們?cè)诰€交談!