宣告並使用基本列舉

列舉可以被認為是密封類的語法糖,它只在編譯時被例項化多次以定義一組常量。

列出不同季節的簡單列舉將宣告如下:

public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

雖然列舉常量不一定需要全部大寫,但 Java 約定是常量的名稱完全是大寫的,單詞用下劃線分隔。

你可以在自己的檔案中宣告列舉:

/**
 * This enum is declared in the Season.java file.
*/
public enum Season {
    WINTER,
    SPRING,
    SUMMER,
    FALL
}

但是你也可以在另一個類中宣告它:

 public class Day {

    private Season season;

    public String getSeason() {
        return season.name();
    }

    public void setSeason(String season) {
        this.season = Season.valueOf(season);
    }

    /**
     * This enum is declared inside the Day.java file and 
     * cannot be accessed outside because it's declared as private.
     */
    private enum Season {
        WINTER,
        SPRING,
        SUMMER,
        FALL
    }

}

最後,你不能在方法體或建構函式中宣告列舉:

public class Day {

    /**
     * Constructor
    */
    public Day() {
        // Illegal. Compilation error
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }
    }

    public void aSimpleMethod() {
        // Legal. You can declare a primitive (or an Object) inside a method. Compile!
        int primitiveInt = 42;

        // Illegal. Compilation error.
        enum Season {
            WINTER,
            SPRING,
            SUMMER,
            FALL
        }

        Season season = Season.SPRING;
    }
    
}

不允許重複的列舉常量:

public enum Season {
    WINTER,
    WINTER, //Compile Time Error : Duplicate Constants
    SPRING,
    SUMMER,
    FALL
} 

列舉的每個常量預設為 publicstaticfinal 。由於每個常量都是 static,因此可以使用列舉名稱直接訪問它們。

列舉常量可以作為方法引數傳遞:

public static void display(Season s) {
    System.out.println(s.name());  // name() is a built-in method that gets the exact name of the enum constant
}

display(Season.WINTER);  // Prints out "WINTER"

你可以使用 values() 方法獲取列舉常量陣列。保證值在返回的陣列中按宣告順序排列:

Season[] seasons = Season.values();

注意:此方法在每次呼叫時都會分配一個新的值陣列。

迭代列舉常量:

public static void enumIterate() {
    for (Season s : Season.values()) {
        System.out.println(s.name());
    }
}

你可以在 switch 語句中使用列舉:

public static void enumSwitchExample(Season s) {
    switch(s) {
        case WINTER:
            System.out.println("It's pretty cold");
            break;
        case SPRING:
            System.out.println("It's warming up");
            break;
        case SUMMER:
            System.out.println("It's pretty hot");
            break;
        case FALL:
            System.out.println("It's cooling down");
            break;
    }
}

你還可以使用 == 比較列舉常量:

Season.FALL == Season.WINTER    // false
Season.SPRING == Season.SPRING  // true

比較列舉常量的另一種方法是使用如下的 equals(),這被認為是不好的做法,因為你很容易陷入陷阱,如下所示:

Season.FALL.equals(Season.FALL); // true
Season.FALL.equals(Season.WINTER); // false
Season.FALL.equals("FALL"); // false and no compiler error

此外,雖然 enum 中的例項集不能在執行時更改,但例項本身並不是固有不可變的,因為與任何其他類一樣,enum 可以包含可變欄位,如下所示。

public enum MutableExample {
    A,
    B;

    private int count = 0;

    public void increment() {
        count++;
    }

    public void print() {
        System.out.println("The count of " + name() + " is " + count);
    }
}

// Usage:
MutableExample.A.print();       // Outputs 0
MutableExample.A.increment();
MutableExample.A.print();       // Outputs 1 -- we've changed a field   
MutableExample.B.print();       // Outputs 0 -- another instance remains unchanged

但是,一個好的做法是使 enum 例項不可變,即當它們沒有任何額外的欄位或者所有這些欄位都標記為 final 並且它們本身是不可變的。這將確保在應用程式的生命週期內,enum 不會洩漏任何記憶體,並且在所有執行緒中使用其例項是安全的。

列舉隱含地實現了 SerializableComparable,因為 Enum 類具有:

public abstract class Enum<E extends Enum<E>>
extends Object
implements Comparable<E>, Serializable