enum定以的类型就是一个类,一个类,一个类。重要的事情说三遍。用javac编译好enum类型后,会看到一个xxx.class文件,表明enum类型也是一个类。
本文中,我们用一个普通类去定义常量,模拟、对比用enum定义的常量,可以帮我们更容易理解enum类型是如何工作的。
enum跟class关键字一样,都是定义了一个类,只是这个类有点特殊,他有以下特点:
1. enum定义的这个类里边定义了一组常量(static final),并且每个常量的类型都是enum定义的这个类本身,并且这些常量都指向enum定义的这个类(或其子类)的对象(这些常量本身是对象的引用)。
2. 我们用普通类定义的的静态成员变量,长这样:
class Day{
private int dayOfWeek;
public static final Day Monday = new Day(0);
public static final Day Tuestday= new Day(1);
...
Day(int day){
this.dayOfWeek = day;
}
...
}
而用enum定义的类中定义的常量是下边这样:
enum Day{
Monday, Tuesday, Wendesday ....;
}
其实他们是一回事。enum定义的类,里边的常量,你不需要显示的加上static final,然后用new创建一个对象赋给这些静态常量,这一切都由编译器给你做好。这就相当于一个语法糖。上边enum类里边定义的Monday, Tuesday, Wendesday等静态成员变量,实际上也会关联一个数字,只是不需要我们显式的通过new Day(0)或者Monday(0)来指定,编译器会帮我们搞定。
但有时候,我们希望用enum定义的常量,不仅仅是一个简单的常量,我们希望它关联更多的数据,这时我们会使用类似下边的语法,就是往enum定义的类里边添加更多的非静态成员变量:
enum Day{
//每天上的课程
private final String[] courses;
Monday("语文","数学","英语"),
Tuesday("体育","数学","英语"),
Wendesday("化学","物理","英语")
....;
CoursesOfDay(String ... courses){
this.courses = courses;
}
}
我们可以看到在这个例子中, Monday等常量不仅仅隐式的关联的一个整数变量,我们还显式的在这个类里边定义了一个数组,表示每天的课程表。如果你愿意,甚至还可以定义更多的非静态成员变量,这样每一个常量(实际上是一个该enum类的对象的引用)就可以关联到更多的数据。使用常量时,可以像这样:
System.out.println(Day.Monday.getCourses());
3. 这个用enum定义的类可以有多个非静态成员变量,但都必须是immutable的,也就是用final修饰。比如上边我们的courses变量用final修饰。
4. enum类的构造方法私有
5. enum定以的类默认拥有public的values()方法,返回的是一个数组,数组里边包含了所有我们之前定义的常量。
6. 这些常量的默认的toString()方法是打印跟常量同名的字符串,比如打印Day.Monday,输出结果就是Monday。可以覆写enum类型的toString()方法,改成自己期望的值,比如我们下边给出的示例toString()就打印了别的信息,不是常量名字本身。
7. enum类里边的静态常量不一定是该enum 类的对象,也可以是enum类的子类对象。比如下边代码中例子,每个static常量对象,都是一个重写了apply()抽象方法的子类对象。这样做的好处是防止以后添加新的常量时,没有添加该常量对应的动作。
下边的类似,参考了《effective java》中的一个例子,稍微有一点复杂。但是如果你能从类的角度去理解enum定义的类型,就很容易理解,而且enum定义的的确是类哦,只不过这个类里边有一些静态引用类型的常量,指向了一些类型本身的对象:
package enumeration;
public class EnumDemo2 {
public static void main(String[] args) {
double x = 10.36;
double y = 2.37;
//使用enum
Operation[] values = Operation.values();
for (Operation operation : values) {
System.out.println("x " + operation + " y = " + operation.apply(x, y));
}
System.out.println("*****************");
//使用自定义普通类代替enum
Operator1[] values1 = Operator1.values();
for (Operator1 operation : values1) {
System.out.println("x " + operation + " y = " + operation.apply(x, y));
}
}
}
//enum类型
enum Operation {
//这里,常量指向的是子类的对象,这里使用了类似于匿名类的方式来给这些常量赋值。
//Operation PLUS = new Operation(){ 覆写的方法 ... }
PLUS("+") {
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
public double apply(double x, double y) {
return x - y;
}
},
MULTIPLY("*"){
public double apply(double x, double y) {
return x * y;
}
},
DEVIDE("/"){
public double apply(double x, double y) {
return x / y;
}
};
private final String opertator;
Operation(String operator) {
this.opertator = operator;
}
public abstract double apply(double x, double y);
@Override
public String toString() {
// TODO Auto-generated method stub
return opertator;
}
}
//自定义类,可以实现跟enum类的类似的功能。
abstract class Operator1 {
public static final Operator1 PLUS = new Operator1("+") {
public double apply(double x, double y) {
return x + y;
}
};
public static final Operator1 MINUS = new Operator1("-") {
public double apply(double x, double y) {
return x - y;
}
};
public static final Operator1 MULTIPLY = new Operator1("*") {
public double apply(double x, double y) {
return x * y;
}
};
public static final Operator1 DIVIDE = new Operator1("/") {
public double apply(double x, double y) {
return x / y;
}
};
private final String opertator;
Operator1(String operator) {
this.opertator = operator;
}
public abstract double apply(double x, double y);
@Override
public String toString() {
// TODO Auto-generated method stub
return opertator;
}
public static Operator1 [] values() {
Operator1 [] values = new Operator1[4];
values[0] = PLUS;
values[1] = MINUS;
values[2] = MULTIPLY;
values[3] = DIVIDE;
return values;
}
}
output:
-----------
x + y = 12.73
x - y = 7.989999999999999
x * y = 24.5532
x / y = 4.371308016877637
*****************
x + y = 12.73
x - y = 7.989999999999999
x * y = 24.5532
x / y = 4.371308016877637