枚举类型 是一组固定常量组成合法值的类型,比如一年中的季节,一周中的星期。
不使用枚举时定义常量的方法通常是这样:
public final class Week {
public static final int WEEK_MONDAY = 1;
public static final int WEEK_TUESDAY = 2;
public static final int WEEK_WEDNESDAY = 3;
public static final int WEEK_THURSDAY = 4;
public static final int WEEK_FRIDAY = 5;
public static final int WEEK_SATURDAY = 6;
public static final int WEEK_SUNDAY = 7;
}
这种方法称作int枚举模式,这种方式有些缺点:
setWeek(10)
或者setWeek(MONTH_JANUARY)
在语法上都是合法的,但你的本意并非如此。java1.5开始java提供一种新的引用类型 – 枚举类型(enum type)
/**
* 定义了加、减、乘、除 操作
*/
public enum Operation {
PLUS, MINUS, TIMES, DIVIDE
}
//计算并打印结果
public static void calc(int num1, int num2, Operation op) {
switch (op) {
case PLUS:
System.out.println(num1 + " + " + num2 + " = "+num1 + num2);
break;
case MINUS:
System.out.println(num1 - num2);
break;
case TIMES:
System.out.println(num1 * num2);
break;
case DIVIDE:
System.out.println(num1 / num2);
break;
default:
throw new RuntimeException();
}
}
//调用计算方法
calc(1, 2, Operation.PLUS);//输出: 1 + 2 = 12
其中的
PLUS
MINUS
等都是Operation
类型,因此可以避免上面int枚举模式中类型安全问题,
可以利用编译器检查出类型不匹配。
使用javap反编译上面的Operation.class
得到下面代码
public final class com.erick.hello.Operation extends java.lang.Enum<com.erick.hello.Operation> {
public static final com.erick.hello.Operation PLUS;
public static final com.erick.hello.Operation MINUS;
public static final com.erick.hello.Operation TIMES;
public static final com.erick.hello.Operation DIVIDE;
static {};
public static com.erick.hello.Operation[] values();
public static com.erick.hello.Operation valueOf(java.lang.String);
}
通过上面反编译的结果可以知道:
java.lang.Enum
, Enum
实现了Comparable
Serializable
这两个接口。values()
valueOf(String)
Operation
类型的实例除了完善了int枚举类型的不足之外,枚举类型还可以添加任意的方法和属性,并且可以实现任意接口。
添加任意方法的原因可能是想要将数据或者操作与对应的常量关联。
/**
* 定义了加、减、乘、除 操作
*/
public enum Operation {
//枚举常量的定义必须在第一行,最后一个常量后面加分号,后面是定义的属性和方法
PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/");
private String op;
private Operation(String op) {
this.op = op;
}
public String getOP() {
return op;
}
public void calc(int num1, int num2) {
switch (this) {
case PLUS:
System.out.println(num1 + op + num2 + " = " + (num1 + num2));
break;
case MINUS:
System.out.println(num1 - num2);
break;
case TIMES:
System.out.println(num1 * num2);
break;
case DIVIDE:
System.out.println(num1 / num2);
break;
default:
throw new RuntimeException();
}
}
}
//测试
Operation.PLUS.calc(1, 2);
//输出:1+2 = 3
上面的例子中如果想要增加一个开方运算,就需要增加一个开方枚举,并在switch case 中加一个分支来做具体运算。
但是这样很容易只添加了开方枚举,但忘记了具体运算的实现,而且能够顺利编译。下面的方法可以尽量避免这一情况。
public enum Operation {
PLUS("+") {
@Override
void calc(int num1, int num2) {
System.out.println(num1 + this.getOP() + num2 + " = " + (num1 + num2));
}
},
MINUS("-") {
@Override
void calc(int num1, int num2) {
System.out.println(num1 + this.getOP() + num2 + " = " + (num1 + num2));
}
};
private String op;
private Operation(String op) {
this.op = op;
}
public String getOP() {
return op;
}
abstract void calc(int num1, int num2);
}
//比较此枚举与指定对象的顺序。
int compareTo(E o)
//返回与此枚举常量的枚举类型相对应的 Class 对象。
Class getDeclaringClass()
//返回此枚举常量的名称,在其枚举声明中对其进行声明。
String name()
//与name()返回一致
String toString()
//返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。
int ordinal()
//返回带指定名称的指定枚举类型的枚举常量。
static > T valueOf(String name)
//测试
for(Operation o : Operation.values()){
System.out.println(o.ordinal() + " : " + o.name() + " : " + o.getDeclaringClass());
}
// 输出:
// 0 : PLUS : class com.erick.hello.Operation
// 1 : MINUS : class com.erick.hello.Operation
// 2 : TIMES : class com.erick.hello.Operation
// 3 : DIVIDE : class com.erick.hello.Operation
大多数情况下不需要使用这个方法,这个方法的设计是用于像EnumSet和EnumMap这种基于枚举通用数据结构的,
除非是编写这些数据结构,否则应该避免使用ordinal方法。如果需要枚举与一个int值绑定,应该使用枚举实例的属性来绑定。
public enum Week {
WEEK_MONDAY(1), WEEK_TUESDAY(2);
private int num;
Week(int num) {
this.num = num;
}
}
枚举类型不能被继承,这是语言特性,而且枚举是用来表示有限数量的对象,因此大多情况下并不需要扩展。
但有些情况,比如一些特特定操作,当下只包括了所有操作的一部分就可以满足需求,
但需要更多操作时就需要扩展。
上面的计算器例子中,实现了计算器的加、减、乘、除操作,但之后又需要一个求幂的操作,
这时可以实现一个操作接口,来实现可扩展的特性。
//操作接口
public interface Operation {
void calc(int num1, int num2);
}
//基础计算枚举
public enum BasicOperation implements Operation{
//....省略了减法和乘除。
PLUS("+") {
@Override
public void calc(int num1, int num2) {
System.out.println(num1 + this.getOP() + num2 + " = " + (num1 + num2));
}
};
private String op;
private BasicOperation(String op) {
this.op = op;
}
public String getOP() {
return op;
}
}
//扩展一个幂运算
public enum ExtendedOperation implements Operation{
PLUS("^") {
@Override
public void calc(int num1, int num2) {
System.out.println(num1 + this.getOP() + num2 + " = " + Math.pow(num1, num2));
}
};
private String op;
private ExtendedOperation(String op) {
this.op = op;
}
public String getOP() {
return op;
}
}
只要API通过接口的方式操作,就可以允许客户端扩展自己的操作方式。