JAVA 枚舉詳解
java 枚舉類型的基本想法非常簡單:這些類通過共有的靜態final域爲每個枚舉常量導出一個實例。枚舉類型沒有可以訪問的構造器,所以它是真的final類。客戶端不能創建枚舉類型的實例,也不能對它進行擴展,因此不存實例,而只存在聲明過程的枚舉常量。也就是枚舉類型是實例受控的。它們是單例(Singleton)的範型化,本質上是單元素的枚舉。
枚舉類型保證了編譯時的類型安全。包含同名常量的多個枚舉類型可以在一個系統中和平共處。因爲每個類型都有自己的命名空間。可以新增或者重新排列枚舉類型中的常量,而無需重新編譯它的客戶端代碼。
枚舉類型可以添加任意的方法和域,並實現任意的接口。它們提供了所有的Object方法的高級實現,實現了Comparable和Serializable接口,並針對枚舉類型的可任意改變性提供了序列化方法。
舉個例子,如定義一個狀態類型枚舉類,代碼如下:
public enum StatusPublicEnum {
FAIL("失敗", "300", "認證系統"),
OK("成功", "200", "認證系統");
private final String msg;
private final String status;
private final String code;
StatusPublicEnum(String msg, String status, String code) {
this.msg = msg;
this.status = status;
this.code = code;
}
public String toJson() throws Exception {
JSONObject jsonObject = new JSONObject();
jsonObject.put("msg",this.msg);
jsonObject.put("status",this.status);
jsonObject.put("code",this.code);
return jsonObject.toCompactString();
}
public static void main(String[] args) throws Exception {
System.out.println(StatusPublicEnum.FAIL.toJson());
System.out.println(StatusPublicEnum.OK.toJson());
}
}
說明:在枚舉類型StatusPublicEnum
中添加了toJson
方法,該方法返回了枚舉類中定義三個屬性的JSON串。我們使用時可以直接調用StatusPublicEnum.OK.toJson()
方法,返回OK枚舉對象的JSON串。返回結果如下
{"msg":"失敗","status":"300","code":"認證系統"}
{"msg":"成功","status":"200","code":"認證系統"}
StatusPublicEnum實例對於大多數枚舉類型來說足夠了,但是我們有時候會需要更多的方法。每個常量關聯了不同的數據類型,但有時需要將不同的行爲與每個常量關聯起來。例如我們編寫一個枚舉類型,來表示計算器的四大基本操作,你想要提供一個方法來執行每個常量所表示的算術運算。有一種方式是通過啓用枚舉的值來實現。
/**
* 枚舉計算類
*/
public enum Operation {
PLUS, MINUS, TIMES, DIVIDE;
public double apply(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
}
throw new AssertionError("Unknown op:" + this);
}
public static void main(String[] args) {
System.out.println(Operation.PLUS.apply(2, 3));
}
}
這段代碼能用,但是不太好看。如果沒有 throw 語句,它就不能進行編譯,雖然從技術角度來看代碼的結束部分是可以執行的,但是實際上是不可能執行到這行代碼的。更糟糕的是,這段代碼很脆弱。如果新增一個枚舉常量,卻忘記給switch添加相應的條件,枚舉類型可以編譯,但是運行新的枚舉常量時,運行就會失敗。
讓我們改進這個方法,在枚舉類型中聲明一個抽象的apply方法,並在特定於常量的類主體中,用具體的方法覆蓋每個常量的抽象apply方法。這種方法被稱爲特定於常量的方法實現。
/**
* 枚舉計算類
*/
public enum Operation {
PLUS("+") {
@Override
public double apply(double x, double y) {
return x + y;
}
}, MINUS("-") {
@Override
public double apply(double x, double y) {
return x - y;
}
}, TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
}, DIVIDE("/") {
@Override
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
public abstract double apply(double x, double y);
@Override
public String toString() {
return symbol;
}
public static void main(String[] args) {
double x = 4;
double y = 2;
for (Operation operation : Operation.values()) {
System.out.printf("%f %s %f = %f%n",
x, operation, y, operation.apply(x, y));
}
}
}
通過接口擴展枚舉
雖然枚舉類型是不可擴展的,但是接口類型確實可擴展的,它是用來表示API中的操作的接口類型。你可以定義另一個枚舉類型,它實現這個接口,並用這個新類型的實例代替基本類型。
定義接口:
public interface IOperation {
double apply(double x, double y);
}
枚舉實現:
/**
* 枚舉計算類
*/
public enum Operation implements IOperation{
PLUS("+") {
@Override
public double apply(double x, double y) {
return x + y;
}
}, MINUS("-") {
@Override
public double apply(double x, double y) {
return x - y;
}
}, TIMES("*") {
@Override
public double apply(double x, double y) {
return x * y;
}
}, DIVIDE("/") {
@Override
public double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public static void main(String[] args) {
double x = 4;
double y = 2;
for (Operation operation : Operation.values()) {
System.out.printf("%f %s %f = %f%n",
x, operation, y, operation.apply(x, y));
}
}
}
擴展實現乘積運算:
public enum ExtOperation implements IOperation {
EXP("^") {
@Override
public double apply(double x, double y) {
return Math.pow(x, y);
}
};
private final String symbol;
ExtOperation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return this.symbol;
}
//入參實現IOperation接口並且是枚舉類型。這個可以將該限定去掉,只要實現IOperation接口即可。
private static <T extends Enum<T> & IOperation> void test(Class<T> tClass, double x,
double y) {
for (IOperation operation : tClass.getEnumConstants()) {
System.out.printf("%f %s %f = %f%n",
x, operation, y, operation.apply(x, y));
}
}
public static void main(String[] args) {
test(ExtOperation.class,2,3);//使用擴展實現枚舉對象
test(Operation.class,2,3);//使用默認的實現
}
}