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);//使用默认的实现
    }

}
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页