JAVA 枚舉詳解(枚舉基本使用高級用法枚舉擴展)

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);//使用默認的實現
    }

}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章