枚舉(enum)

轉(zhuǎn)載:https://segmentfault.com/a/1190000007688908

枚舉類

實(shí)例有限而且固定的類,在Java里被稱為枚舉類。

早期采用通過定義類的方式來實(shí)現(xiàn)雷袋,可以采用如下設(shè)計(jì)方式

  • 通過private將構(gòu)造器隱藏起來
  • 把這個(gè)類的所有可能實(shí)例都使用public static final 修飾的類變量來保存
  • 如果與必要,可以提供一些靜態(tài)方法彰阴,允許其他程序根據(jù)特定參數(shù)來獲取與之匹配的實(shí)例
  • 使用枚舉類可以使程序更加健壯凭涂,避免創(chuàng)建對象的隨意性
    Java從JDK1.5后就增加了對枚舉類的支持。
枚舉類入門

Java5新增了一個(gè)enum關(guān)鍵字(它與class救赐、interface關(guān)鍵字的地位相同)涧团,用以定義枚舉類。枚舉類是一種特殊的類净响,它一樣可以有自己的成員變量少欺、方法,可以實(shí)現(xiàn)一個(gè)或多個(gè)接口馋贤,也可以定義自己的構(gòu)造器赞别。一個(gè)Java源文件中最多只能定義一個(gè)public訪問權(quán)限的枚舉類,且該Java源文件也必須和該枚舉類的類名相同配乓。

  • 枚舉類可以實(shí)現(xiàn)一個(gè)或多個(gè)接口仿滔,使用enum定義的枚舉類默認(rèn)繼承了java.lang.Enum類,而不是默認(rèn)繼承Object類犹芹,因此枚舉類不能顯示繼承其他父類崎页。其中java.lang.Enum類實(shí)現(xiàn)了java.lang.Serializable和java.lang.Comparable兩個(gè)接口。
  • 使用enum定義腰埂、非抽象的枚舉類默認(rèn)會(huì)使用final修飾飒焦,因此枚舉類不能派生子類。
    枚舉類的構(gòu)造器只能使用private訪問控制符,如果省略了構(gòu)造器的訪問控制符牺荠,則默認(rèn)使用private修飾翁巍;如果強(qiáng)制指定訪問控制符,則只能指定private修飾符休雌。
  • 枚舉類的所有實(shí)例必須在枚舉類的第一行顯式列出灶壶,否則這個(gè)枚舉類永遠(yuǎn)都不能產(chǎn)生實(shí)例。列出這些實(shí)例時(shí)杈曲,系統(tǒng)會(huì)自動(dòng)添加public static final 修飾驰凛,無須程序員顯式添加。
    枚舉類默認(rèn)提供了一個(gè)values()方法担扑,該方法可以很方便地遍歷所有的枚舉值恰响。
public enum SeasonEnum
{
    //在第一行列出4個(gè)枚舉實(shí)例
    SPRING,SUMMER,FALL,WINTER;
}

編譯上面Java程序,將生成一個(gè)SeasonEnum.class文件魁亦,這表明枚舉類是一個(gè)特殊的Java類渔隶。
所有的枚舉值之間以英文逗號(hào)(,)隔開,枚舉值列舉結(jié)束后以英文分號(hào)作為結(jié)束洁奈。這些枚舉值代表了該枚舉類的所有可能的實(shí)例间唉。

public class EnumTest 
{
    public void judge(SeasonEnum s)
    {
        //switch語句里的表達(dá)式可以是枚舉值
        switch(s)
        {
            case SPRING:
                System.out.println("春之櫻");
                break;
            case SUMMER:
                System.out.println("夏之蟬");
                break;
            case FALL:
                System.out.println("秋之楓");
                break;
            case WINTER:
                System.out.println("冬之雪");
                break;
        }
    }
    public static void main(String[] args) 
    {
        //枚舉類默認(rèn)有一個(gè)values()方法,返回該枚舉類的所有實(shí)例
        for(SeasonEnum s : SeasonEnum.values())
        {
            System.out.println(s);
        }
        //使用枚舉實(shí)例時(shí)利术,可通過EnumClass.variable形式來訪問
        new EnumTest().judge(SeasonEnum.SPRING);
    }
}

當(dāng)switch控制表達(dá)式使用枚舉類型時(shí)呈野,后面case表達(dá)式中的值直接使用枚舉值的名字,無須添加枚舉類作為限定印叁。
java.lang.Enum類中提供了如下幾個(gè)方法:

  • int compareTo(E o):該方法用于與指定枚舉對象比較順序被冒,同一個(gè)枚舉實(shí)例只能與相同類型的枚舉實(shí)例進(jìn)行比較。如果該枚舉對象位于指定枚舉對象之后轮蜕,則返回正整數(shù)昨悼;如果該枚舉對象位于指定枚舉對象之前,則返回負(fù)整數(shù)跃洛,否則返回零率触。
  • String name():返回此枚舉實(shí)例的名稱,這個(gè)名稱就是定義枚舉類時(shí)列出的所有枚舉值之一汇竭。與此方法相比葱蝗,大多數(shù)程序員應(yīng)該優(yōu)先考慮使用toString()方法,因?yàn)閠oString()方法返回更加用戶友好的名稱细燎。
    int ordinal():返回枚舉值在枚舉類中的索引值(就是枚舉值在枚舉聲明中的位置两曼,第一個(gè)枚舉值的索引值為零)。
  • String toString():返回枚舉常量的名稱玻驻,與name方法相似悼凑,但toString()方法更常用。
  • public static <T extends Enum <T>> T valueOf(Class<T>enumType, String name):這是一個(gè)靜態(tài)方法,用于返回指定枚舉類中指定名稱的枚舉值户辫。名稱必須與在該枚舉類中聲明枚舉值時(shí)所用的標(biāo)識(shí)符完全匹配益老,不允許使用額外的空白字符。

當(dāng)程序使用System.out.println(s)語句來打印枚舉值時(shí)寸莫,實(shí)際上輸出的是該枚舉值的toString()方法,也就是輸出該枚舉值的名字档冬。

枚舉類的成員變量膘茎、方法和構(gòu)造器

枚舉類的實(shí)例只能是枚舉值,而不是隨意地通過new來創(chuàng)建枚舉類對象酷誓。

public enum Gender 
{
    MALE,FEMALE;
    //定義一個(gè)public修飾的實(shí)例變量
    private String name;
    public void setName(String name) 
    {
        switch (this) {
        case MALE:
            if (name().equals("男")) 
            {
                this.name = name;
            }
            else 
            {
                System.out.println("參數(shù)錯(cuò)誤");
                return;
            }
            break;
        case FEMALE:
            if (name().equals("女")) 
            {
                this.name = name;
            }
            else 
            {
                System.out.println("參數(shù)錯(cuò)誤");
                return;
            }
            break;
        }
    }
    public String getName() 
    {
        return this.name();
    }
}

public class GenderTest 
{
    public static void main(String[] args) 
    {
        //通過Enum的valueOf()方法來獲取指定枚舉類的枚舉值
        //Gender gender = Enum.valueOf(Gender.class, "FEMALE");
        Gender g = Gender.valueOf("FEMALE");
        g.setName("女");
        System.out.println(g+"代表:"+g.getName());
        g.setName("男");
        System.out.println(g+"代表:"+g.getName());
    }
}

枚舉類通常應(yīng)該設(shè)計(jì)成不可變類披坏,成員變量值不允許改變,將枚舉類的成員變量都使用private final修飾盐数。如果將所有的成員變量都使用final修飾符來修飾棒拂,必須在構(gòu)造器里為這些成員變量指定初始值,為枚舉類顯式定義帶參數(shù)的構(gòu)造器玫氢。

一旦為枚舉類顯式定義了帶參數(shù)的構(gòu)造器帚屉,列出枚舉值時(shí)就必須對應(yīng)地傳入?yún)?shù)。

public enum Gender 
{
    //此處的枚舉值必須調(diào)用對應(yīng)的構(gòu)造器來創(chuàng)建
    MALE("男"),FEMAL("女");
    private final String name;
    private Gender(String name)
    {
        this.name =name;
    }
    public String getName()
    {
        return this.name();
    }
}
實(shí)現(xiàn)接口的枚舉類

枚舉類也可以實(shí)現(xiàn)一個(gè)或多個(gè)接口漾峡。與普通類實(shí)現(xiàn)一個(gè)或多個(gè)接口完全一樣攻旦,枚舉類實(shí)現(xiàn)一個(gè)或多個(gè)接口時(shí),也需要實(shí)現(xiàn)該接口所包含的方法生逸。

public interface GenderDesc
{
    void info();
}

如果由枚舉類來實(shí)現(xiàn)接口里的方法牢屋,則每個(gè)枚舉值在調(diào)用該方法時(shí)都有相同的行為方式(因?yàn)榉椒w完全一樣)族扰。如果需要每個(gè)枚舉值在調(diào)用該方法時(shí)呈現(xiàn)出不同的行為方式摊唇,則可以讓每個(gè)枚舉值分別來實(shí)現(xiàn)該方法缀皱,每個(gè)枚舉值提供不同的實(shí)現(xiàn)方式蝎宇,從而讓不同的枚舉值調(diào)用該方法時(shí)具有不同的行為方式朦肘。

public enum Gender implements GenderDesc
{
    // 此處的枚舉值必須調(diào)用對應(yīng)構(gòu)造器來創(chuàng)建
    MALE("男")
    // 花括號(hào)部分實(shí)際上是一個(gè)類體部分
    {
        public void info()
        {
            System.out.println("這個(gè)枚舉值代表男性");
        }
    },
    FEMALE("女")
    {
        public void info()
        {
            System.out.println("這個(gè)枚舉值代表女性");
        }
    };
    // 其他部分與codes\06\6.9\best\Gender.java中的Gender類完全相同
    private final String name;
    // 枚舉類的構(gòu)造器只能使用private修飾
    private Gender(String name)
    {
        this.name = name;
    }
    public String getName()
    {
        return this.name;
    }
    // 增加下面的info()方法侥衬,實(shí)現(xiàn)GenderDesc接口必須實(shí)現(xiàn)的方法
    public void info()
    {
        System.out.println(
            "這是一個(gè)用于用于定義性別的枚舉類");
    }
}

當(dāng)創(chuàng)建MALE和FEMALE兩個(gè)枚舉值時(shí)势篡,后面又緊跟了一對花括號(hào)溪厘,這對花括號(hào)里包含了一個(gè)info()方法定義狮鸭『辖粒花括號(hào)部分實(shí)際上就是一個(gè)類體部分,在這種情況下歧蕉,當(dāng)創(chuàng)建MALE和FEMALE枚舉值時(shí)灾部,并不是直接創(chuàng)建Gender枚舉類的實(shí)例,而是相當(dāng)于創(chuàng)建Gender的匿名子類的實(shí)例惯退。

并不是所有的枚舉類都使用了final修飾赌髓。非抽象的枚舉類才默認(rèn)使用final修飾。對于一個(gè)抽象的枚舉類而言——只要它包含了抽象方法,它就是抽象枚舉類锁蠕,系統(tǒng)會(huì)默認(rèn)使用abstract修飾夷野,而不是使用final修飾。

編譯上面的程序荣倾,生成了Gender.class悯搔、Gender$1.class和Gender$2.class三個(gè)文件,證明了:MALE和FEMALE實(shí)際上是Gender匿名子類的實(shí)例舌仍,而不是Gender類的實(shí)例妒貌。當(dāng)調(diào)用MALE和FEMALE兩個(gè)枚舉值的方法時(shí),就會(huì)看到兩個(gè)枚舉值的方法表現(xiàn)不同的行為方式铸豁。

包含抽象方法的枚舉類
public enum Operation 
{
    PLUS
    {
        public double eval(double x, double y) 
        {
            return x + y;
        }
    },
    MINUS
    {
        public double eval(double x, double y) 
        {
            return x - y;
        }
    },
    TIMES
    {
        public double eval(double x, double y) 
        {
            return x * y;
        }
    },
    DIVIDE
    {
        public double eval(double x, double y) 
        {
            return x / y;
        }
    };
    //為枚舉類定義一個(gè)抽象方法
    //這個(gè)抽象方法由不同的枚舉值提供不同的實(shí)現(xiàn)
    public abstract double eval(double x, double y);
    public static void main(String[] args) 
    {
        System.out.println(Operation.PLUS.eval(3, 4));
        System.out.println(Operation.MINUS.eval(5, 4));
        System.out.println(Operation.TIMES.eval(8, 8));
        System.out.println(Operation.DIVIDE.eval(1, 5));
    }
}

枚舉類里定義抽象方法時(shí)不能使用abstract關(guān)鍵字將枚舉類定義成抽象類(因?yàn)橄到y(tǒng)自動(dòng)會(huì)為它添加abstract關(guān)鍵字)灌曙,但因?yàn)槊杜e類需要顯式創(chuàng)建枚舉值,而不是作為父類节芥,所以定義每個(gè)枚舉值時(shí)必須為抽象方法提供實(shí)現(xiàn)在刺,否則將出現(xiàn)編譯錯(cuò)誤。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末头镊,一起剝皮案震驚了整個(gè)濱河市蚣驼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拧晕,老刑警劉巖隙姿,帶你破解...
    沈念sama閱讀 222,104評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異厂捞,居然都是意外死亡输玷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,816評論 3 399
  • 文/潘曉璐 我一進(jìn)店門靡馁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來欲鹏,“玉大人,你說我怎么就攤上這事臭墨∨夂浚” “怎么了?”我有些...
    開封第一講書人閱讀 168,697評論 0 360
  • 文/不壞的土叔 我叫張陵胧弛,是天一觀的道長尤误。 經(jīng)常有香客問我,道長结缚,這世上最難降的妖魔是什么损晤? 我笑而不...
    開封第一講書人閱讀 59,836評論 1 298
  • 正文 為了忘掉前任,我火速辦了婚禮红竭,結(jié)果婚禮上尤勋,老公的妹妹穿的比我還像新娘喘落。我一直安慰自己,他們只是感情好最冰,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,851評論 6 397
  • 文/花漫 我一把揭開白布瘦棋。 她就那樣靜靜地躺著,像睡著了一般暖哨。 火紅的嫁衣襯著肌膚如雪赌朋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,441評論 1 310
  • 那天篇裁,我揣著相機(jī)與錄音箕慧,去河邊找鬼。 笑死茴恰,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的斩熊。 我是一名探鬼主播往枣,決...
    沈念sama閱讀 40,992評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼粉渠!你這毒婦竟也來了分冈?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,899評論 0 276
  • 序言:老撾萬榮一對情侶失蹤霸株,失蹤者是張志新(化名)和其女友劉穎雕沉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體去件,經(jīng)...
    沈念sama閱讀 46,457評論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡坡椒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,529評論 3 341
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了尤溜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片倔叼。...
    茶點(diǎn)故事閱讀 40,664評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖宫莱,靈堂內(nèi)的尸體忽然破棺而出丈攒,到底是詐尸還是另有隱情,我是刑警寧澤授霸,帶...
    沈念sama閱讀 36,346評論 5 350
  • 正文 年R本政府宣布巡验,位于F島的核電站,受9級特大地震影響碘耳,放射性物質(zhì)發(fā)生泄漏显设。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,025評論 3 334
  • 文/蒙蒙 一藏畅、第九天 我趴在偏房一處隱蔽的房頂上張望敷硅。 院中可真熱鬧功咒,春花似錦、人聲如沸绞蹦。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,511評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幽七。三九已至景殷,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間澡屡,已是汗流浹背猿挚。 一陣腳步聲響...
    開封第一講書人閱讀 33,611評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留驶鹉,地道東北人绩蜻。 一個(gè)月前我還...
    沈念sama閱讀 49,081評論 3 377
  • 正文 我出身青樓,卻偏偏與公主長得像室埋,于是被迫代替她去往敵國和親办绝。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,675評論 2 359

推薦閱讀更多精彩內(nèi)容

  • 本文包括:枚舉由來如何使用姚淆?枚舉類特性單例設(shè)計(jì)模式定義特殊結(jié)構(gòu)枚舉星期輸出中文的案例枚舉類API 枚舉(enum)...
    廖少少閱讀 2,852評論 2 14
  • 枚舉類 (enum) 在某些情況下孕蝉,一個(gè)類的對象時(shí)有限且固定的,如季節(jié)類腌逢,它只有春夏秋冬4個(gè)對象這種實(shí)例有限且固定...
    AshengTan閱讀 85,926評論 6 49
  • 由于本人能力有限降淮,文中若有錯(cuò)誤之處,歡迎指正搏讶。轉(zhuǎn)載請注明出處:http://www.reibang.com/p/6...
    WaitingAnd閱讀 1,701評論 6 13
  • 枚舉類構(gòu)造器 只能使用 private 訪問修飾符佳鳖,所以無法從外部調(diào)用構(gòu)造器,構(gòu)造器只在構(gòu)造枚舉值時(shí)被調(diào)用媒惕; 使用...
    天空在微笑閱讀 282評論 0 0
  • 裁判要旨 人民法院可以根據(jù)當(dāng)事人的請求對案件所涉商標(biāo)是否為馳名商標(biāo)進(jìn)行認(rèn)定腋颠,以判斷他人的使用行為是否構(gòu)成侵權(quán),從而...
    小好閱讀 355評論 0 1