列舉
Prerequisites:
類別作為列舉
以下程式碼是用類別做的enum,需要有以下條件。
- 建構子全為私有,不可讓其它類別使用new建立。
- 屬性使用public + final + static + 本身類別 屬性大寫 = new 本身類別建構子();
- 建構子的參數都為private,可以提供get,不能提供set。
- 屬性跟著類別的生命周期,類別被載入時就建立。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Gender {
public final static Gender BOY = new Gender("男");
public final static Gender GIRL = new Gender("女");
private String name;
private Gender() {
}
private Gender(String name) {
this.name = name;
}
@Override
public String toString() {
return name;
}
}
使用方法
類別.靜態屬性
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
System.out.println(Gender.BOY);
System.out.println(Gender.GIRL);
}
}
男
女
Enum
改為enum,把class改為enum。
1
public enum Gender1 {}
把以下這段程式碼。
1
public final static Gender BOY = new Gender("男");
改為以下程式碼,都是要放在程式碼最前面,二者都是呼叫一個參數的建構子,只是隱藏public + final + static 。
1
2
3
public enum Gender1 {
BOY("男"); // 放在最前面
}
若有多個屬性,以逗號,
分隔,以分號;
結尾。
1
2
3
public enum Gender1 {
BOY("男"), GIRL("女");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public enum Gender1 {
BOY("男"), GIRL("女");
private String name;
private Gender1() {
}
private Gender1(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public String toString() {
return name;
}
}
使用方法
類別.靜態屬性
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
System.out.println(Gender1.BOY);
System.out.println(Gender1.GIRL);
}
}
男
女
無建構子參數
- 沒有參數就省略圓括號
()
。 - 沒有參數就省略私有建構子,會自動產生。
- BOY與GIRL都是final靜態屬性,屬性類型就是Gender2。
1
2
3
public enum Gender2 {
BOY,GIRL;
}
使用時,沒有參數的建構子,會印出靜態屬性名。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
System.out.println(Gender2.BOY);
System.out.println(Gender2.GIRL);
}
}
BOY
GIRL
Enum的toString()與name()
在Object文章有提過印出物件,也是呼叫toString()的方法,但Enum有對toString()改寫。
在程式碼輸入Enum
,win使用ctrl + b,mac使用cmd + b,進入原始碼。
預設使用name來toString(),若建構子沒參數,name就是屬性名,如上個程式碼Gender2.BOY
,屬性名是BOY。
1
2
3
4
5
6
7
8
9
10
11
12
public abstract class Enum<E extends Enum<E>>
implements Constable, Comparable<E>, Serializable {
private final String name;
public final String name() {
return name;
}
public String toString() {
return name;
}
}
static屬性
使用上一個程式碼,請問建立二個物件,都是使用Gender2.BOY建立的,這二個物件是相等嗎?
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Gender2 boy1 = Gender2.BOY;
Gender2 boy2 = Gender2.BOY;
System.out.println(boy1 == boy2);
}
}
true
由執行結果可以發現,屬性是static,都是指向相同靜態記憶體空間。
ordinal()
印出屬性的順序,預設是從0開始。
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
Gender2 boy = Gender2.BOY;
Gender2 girl = Gender2.GIRL;
System.out.println(boy.ordinal());
System.out.println(girl.ordinal());
}
}
0
1
values()
傳回所有屬性。
1
2
3
public enum Gender2 {
BOY,GIRL;
}
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
Gender2[] arr = Gender2.values();
for (Gender2 val: arr) {
System.out.println(val);
}
}
}
BOY
GIRL
valueOf()
使用字串屬性名,取出靜態屬性物件。
1
2
3
4
5
6
public class Test {
public static void main(String[] args) {
Gender2 boy = Gender2.valueOf("BOY");
System.out.println(boy);
}
}
BOY
若屬性名亂寫,會拋出Error。
1
Gender2 boy = Gender2.valueOf("ABC");
java.lang.IllegalArgumentException:No enum constant enum1.Gender2.ABC
compareTo()
Enum原始檔中的compareTo,比較的是ordinal。
1
2
3
4
5
6
7
8
public final int compareTo(E o) {
Enum<?> other = o;
Enum<E> self = this;
if (self.getClass() != other.getClass() && // optimization
self.getDeclaringClass() != other.getDeclaringClass())
throw new ClassCastException();
return self.ordinal - other.ordinal; // 這行才是重點
}
1
2
3
4
5
6
7
public class Test {
public static void main(String[] args) {
Gender2 boy = Gender2.BOY; // ordinal 0
Gender2 girl = Gender2.GIRL; // ordinal 1
System.out.println(boy.compareTo(girl));
}
}
-1
Enum與javap反編譯
在Intellij用終端機
輸入javap 檔名.class
,以下是反編譯的結果,可以看到Gender2 extends java.lang.Enum
% ls
Gender.class Gender1.class Gender2.class Hobby.class Test.class
% javap Gender2.class
Compiled from "Gender2.java"
public final class enum1.Gender2 extends java.lang.Enum<enum1.Gender2> implements enum1.Hobby {
public static final enum1.Gender2 BOY;
public static final enum1.Gender2 GIRL;
public static enum1.Gender2[] values();
public static enum1.Gender2 valueOf(java.lang.String);
public void hobby();
static {};
}
Enum與介面
因為Enum類別已經繼承Enum,由上一個javap已經證實。
Enum類別不能再繼承其它類別,只能實作介面。
以下是興趣的介面。
1
2
3
interface Hobby {
void hobby();
}
實作Hobby介面。
1
2
3
4
5
6
7
8
9
10
11
12
public enum Gender2 implements Hobby {
BOY,GIRL;
@Override
public void hobby() {
if (this.name() == BOY.name()) {
System.out.println("大部分喜歡玩電動、棒球、運動。");
} else {
System.out.println("大部分喜歡購物、追劇。");
}
}
}
測試
1
2
3
4
5
6
7
8
public class Test {
public static void main(String[] args) {
Gender2 boy = Gender2.BOY;
Gender2 girl = Gender2.GIRL;
boy.hobby();
girl.hobby();
}
}
大部分喜歡玩電動、棒球、運動。
大部分喜歡購物、追劇。