[Java] Enum in Java

enum類別可以單獨宣告或是宣告在其他類別裡面。

單獨宣告:

1
2
3
public enum Direction {
EAST,WEST,SOUTH,NORTH;
}

在編譯時期compiler會自動:

  • 加入final修飾enum和繼承Enum:

    1
    2
    3
    public final enum Direction extends Enum{
    EAST,WEST,SOUTH,NORTH;
    }
  • 加入private Constructor:

    1
    2
    3
    4
    5
    6
    public final enum Direction extends Enum{
    EAST,WEST,SOUTH,NORTH;
    private Direction(String s, int i){
    super(s, i);
    }
    }
  • 加入public static final修飾列舉內容值:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public final enum Direction extends Enum{
    public static final Direction EAST,
    public static final Direction WEST,
    public static final Direction SOUTH,
    public static final Direction NORTH;

    private Direction(String s, int i){
    super(s, i);
    }
    }
  • 初始化:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public final enum Direction extends Enum{
    public static final Direction EAST,
    public static final Direction WEST,
    public static final Direction SOUTH,
    public static final Direction NORTH;

    private Direction(String s, int i){
    super(s, i);
    }

    static{
    EAST = new Direction("EAST", 0);
    WEST = new Direction("WEST", 1);
    SOUTH = new Direction("SOUTH", 2);
    NORTH = new Direction("NORTH", 3);
    }
    }
  • override Enum的valueOf method。

  • 產生一個values method,回傳值為enum類別內容值的陣列。

宣告在其他類別:

1
2
3
4
5
public class DirectionOutter {
public enum Direction {
EAST,WEST,SOUTH,NORTH;
}
}

在編譯時期compiler會自動:

  • 加入static final修飾enum和繼承Enum:
    1
    2
    3
    4
    5
    public class DirectionOutter {
    public static final enum Direction extends Enum {
    EAST,WEST,SOUTH,NORTH;
    }
    }

其餘行為和單獨宣告一樣。


當宣告一個enum類別,compiler會”自動”做那麼多事,會有以下特性:

  1. 自動繼承Enum抽象類別,因為Enum抽象類別實做了ComparableSerializable,所以enum物件之間是可以比較和enum物件是可以序列化。
  2. enum類別不能繼承其他類別或被繼承。
  3. enum物件為Singleton,所以可以使用==或equals進行比較。
  4. enum物件為immutable物件。
  5. 建構子存取權限一定是private。

只有compiler可以繼承Enum。


增加屬性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public enum Direction {
WEST(180),
EAST(0),
NORTH(90),
SOUTH(270);

private Direction(final int angle) {
this.angle = angle;
}

private int angle;

public int getAngle() {
return angle;
}
}

建構子的存取權限可以不加(compiler會自動加入private)或是加入privae。


實作抽象方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public enum Direction {
WEST(180) {
@Override
public void shout() {
System.out.println("WEST");
}
},
EAST(0) {
@Override
public void shout() {
System.out.println("EAST");
}
},
NORTH(90) {
@Override
public void shout() {
System.out.println("NORTH");
}
},
SOUTH(270) {
@Override
public void shout() {
System.out.println("SOUTH");
}
};
public abstract void shout();

Direction(final int angle) {
this.angle = angle;
}

private int angle;

public int getAngle() {
return angle;
}
}

將值轉換成enum

根據使用情境,可以使用valueOf轉換或是自行設計轉化方式。

  • 若想將字串WEST轉換成Direction.WEST:
    使用valueOf

    1
    Direction.valueOf("WEST");
  • 當使用者輸入180度時,要轉換成Direction.WEST:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public enum Direction {
    WEST(180),EAST(0),NORTH(90),SOUTH(270);

    Direction(final int angle) {
    this.angle = angle;
    }

    private int angle;

    public int getAngle() {
    return angle;
    }

    private static final Map<Integer, Direction> lookup = new HashMap<Integer, Direction>();

    static {
    for (Direction s : Direction.values())
    lookup.put(s.getAngle(), s);
    }

    public static Direction get(int angle) {
    return lookup.get(angle);
    }

透過map物件進行轉換。


將enum物件存放到容器:

  • EumSet

    1. 用EnumSet來存放enum物件的時間和空間效能較好。
    2. 在多執行緒實行下是不安全。
    3. enum物件在EnumSet的順序為在宣告時候的順序。
  • EnumMap
    1. 用EnumSet來存放enum物件的時間和空間效能較好。
    2. 在多執行緒實行下是不安全。

      參考資料:

  • Guide for understanding enum in java