1. 程式人生 > >列舉(enum)型別

列舉(enum)型別

關鍵字enum 可以將一組具名的值的有限集合建立一種新的型別,而這些具名的值可以作為常規的程式使用。建立enum 時,編譯器會為你生成一個相關的類,這個類繼承自java.lang.Enum 。下面是一個例子演示了一些Enum 提供的一些功能。

package com.jas.enumtest;

enum Animal{CAT,DOG,SHEEP}

public class EnumClass {
    public static void main(String[] args) {

        for(Animal animal : Animal.values()){
            System.out
.println(animal + " oridinal:" + animal.ordinal()); System.out.print(animal.compareTo(Animal.DOG) + " "); System.out.print(animal.equals(Animal.DOG) + " "); System.out.println(animal == Animal.DOG); System.out.println(animal.getDeclaringClass()); System.out
.println(animal.name()); System.out.println("--------分割線----------"); } for(String str : "DOG,CAT,SHEEP".split(",")){ Animal animal = Animal.valueOf(Animal.class,str); System.out.print(animal + " "); } } }

輸出:
CAT oridinal:0
-1 false false
class com.jas.enumtest.Animal
CAT
——–分割線———-
DOG oridinal:1
0 true true
class com.jas.enumtest.Animal
DOG
——–分割線———-
SHEEP oridinal:2
1 false false
class com.jas.enumtest.Animal
SHEEP
——–分割線———-
DOG CAT SHEEP

      ordinal() 方法返回一個int 型別的值,這個值是enum 在例項中宣告的順序,從0 開始。可以使用 == 來比較enum 例項,編譯器會自動為你提供equals() 方法與 hashCode() 方法。Enum 類實現了Comparable 介面,所以你可以使用compareTo() 方法。同時Enum 類還實現了Serializable 介面。
      getDeclaringClass() 方法返回其所屬的類。
      name 方法返回enum 例項宣告時的名字,這與toString 方法返回的值相同。valueOf() 是在Enum 中定義的static 方法,它可以根據給定的名字返回相應的enum 例項,如果不存在給定名字的例項,就會丟擲異常。

覆蓋enum 的方法
      當我們想要覆蓋enum 中的方法時,我們會發現,它就只有一個方法toString(),當我們覆蓋它時與覆蓋一般的類的方法沒有區別。

enum Animal{
    CAT,DOG,SHEEP;

    @Override
    public String toString() {
        String id = name();
        String lower = id.substring(1).toLowerCase();

        return id.charAt(0) + lower;
    }
}
public class EnumClass {
    public static void main(String[] args) {

        for(Animal animal : Animal.values())
            System.out.print(animal + " ");
    }
}

輸出
Cat Dog Sheep

向enum 中新增方法
      除了不能繼承一個enum 之外,我們基本上可以將enum 看作是一個常規的類。這也意味著enum 擁有自己的建構函式,以及我們可以向enum 中新增方法。它甚至是可以擁有main() 方法。這裡我們通過一個方法返回一個列舉型別的描述不再僅僅是一個toString() 型別的實現。

enum Animal{
    // private String description; 這是不允許的
    CAT("喵喵喵~"),
    DOG("汪汪汪~"),
    SHEEP("咩咩咩~");

    private String description;
    private Animal(String description){
        this.description = description;
    }
    public String getDescription(){
        return description;
    }
}
public class EnumClass {
    public static void main(String[] args) {

        for(Animal animal : Animal.values())
            System.out.println(animal + " : " + animal.getDescription());
    }
}

輸出:
CAT : 喵喵喵~
DOG : 汪汪汪~
SHEEP : 咩咩咩~

      需要注意的是:如果我們打算自定義方法,那麼必須在enum 徐磊例項的後面新增一個分號。同時Java 要求你必須先定義enum 例項,就像上面這樣我們打算在定義enum 例項之前定義description 但是卻得到一個編譯器的錯誤提示。enum 中的建構函式與方法與普通的類沒有任何區別,除了有少量的限制enum 可以說就是一個類。所以我們可以使用enum 做許多額外的事。

switch 語句中的 enum
      一般來說,在switch 語句中 只能使用整數值,而列舉天生就具備整數值的次序,並且可以通過ordinal() 方法獲得其在enum 中的順序,因此我們可以在switch 中使用列舉。

enum Singal{GREEN, YELLOW, RED}

public class TrafficLight {
    Singal color = Singal.RED;

    public void change(){
        switch (color){
            case RED: color = Singal.GREEN;
                break;
            case GREEN: color = Singal.YELLOW;
                break;
            case YELLOW: color = Singal.RED;
                break;
        }
    }
    public String toString(){
        return "The traffic light is : " + color;
    }
    public static void main(String[] args) {

        TrafficLight light = new TrafficLight();
        for (int i = 0; i < 4; i++) {
            System.out.println(light.toString());
            light.change();
        }
    }
}

輸出:
The traffic light is : RED
The traffic light is : GREEN
The traffic light is : YELLOW
The traffic light is : RED

values() 的神祕之處
      我們知道編譯器為我們建立的enum 都繼承自Enum 類。但是如果你去檢視Enum 類就會發現,它並沒有values() 方法。但是我們在上面確實使用了這個方法,這是為什麼呢?下面我們使用反射機制來檢視其中的原因。

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Set;
import java.util.TreeSet;

enum Explore{HERE,THERE}
public class Reflection {
    public static Set<String> analyze(Class<?> enumClass){
        Set<String> set = new TreeSet<>();

        System.out.println("----- Analyzing " + enumClass + " -----");
        for(Type type : enumClass.getGenericInterfaces())
            System.out.println("genericInterface : " + type);
        System.out.println("superClass : " + enumClass.getSuperclass());
        for(Method method : enumClass.getMethods())
            set.add(method.getName());

        System.out.println("----- end -----");
        System.out.println();
        return set;
    }

    public static void main(String[] args) {

        Set<String> exploreMethods = analyze(Explore.class);
        Set<String> enumMethods = analyze(Enum.class);

        System.out.println("exploreMethods : " + exploreMethods);
        System.out.println("enumMethods : " + enumMethods);
        System.out.println("exploreMethods.containsAll(enumMethods): " + exploreMethods.containsAll(enumMethods));
        System.out.println("exploreMethods.removeAll(enumMethods): " + exploreMethods.removeAll(enumMethods));
        System.out.println("exploreMethods : " + exploreMethods);
    }
}

—– Analyzing class com.jas.enumtest.Explore —–
superClass : class java.lang.Enum
—– end —–

—– Analyzing class java.lang.Enum —–
genericInterface : java.lang.Comparable
genericInterface : interface java.io.Serializable
superClass : class java.lang.Object
—– end —–

exploreMethods : [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
enumMethods : [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
exploreMethods.containsAll(enumMethods): true
exploreMethods.removeAll(enumMethods): true
exploreMethods : [values]

      答案就是values() 方法是由編譯器新增的static 方法。其實這個過程中還未其添加了valueOf() 方法。但是Enum 中明明已經有了valueOf() 方法,為什麼編譯器還會為其新增這個方法呢?Enum 中的valueOf() 方法需要傳遞進來兩個引數,但是新增的這個方法只需要傳遞進來一個引數。

                                                                                                            參考書籍:
                                                                                                                《Java 程式設計思想》Bruce Eckel 著 陳昊鵬 譯