Enum作为Sun全新引进的一个关键字,看起来很象是特殊的class, 它也可以有自己的变量,可以定义自己的方法,可以实现一个或者多个接口。当我们在声明一个enum类型时,我们应该注意到enum类型有如下的一些特征。
1. Enum基本特征
举例:
enum Color {
RED, ORANGE, YELLOW, GREEN, CYAN, BLUE, PURPLE;
}
1. 它不能有public的构造函数,这样做可以保证客户代码没有办法新建一个enum的实例。
2. 所有枚举值都是public,static,final的。注意这一点只是针对于枚举值,我们可以和在普通类里面定义变量一样定义其它任何类型的非枚举变量,这些变量可以用任何你想用的修饰符。
3. ordinal()方法:返回枚举值在枚举类种的顺序,这个顺序根据枚举值声明的顺序而定。 示例如下:
Color.RED.ordinal(); //返回结果:0
Color.BLUE.ordinal(); //返回结果:5
4. compareTo()方法:Enum默认实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。示例如下:
Color.RED.compareTo(Color.BLUE); //返回结果 -1
5. values()方法: 静态方法,返回一个包含全部枚举值的数组。示例如下:
Color[] colors = Color.values();
for (Color color : colors) {
System.out.print(color + ",");
}
//返回结果:RED,ORANGE,YELLOW,GREEN,CYAN,BLUE,PURPLE,
6. toString()方法: 返回枚举常量的名称。示例如下:
Color color = Color.RED;
System.out.println(color); //返回结果: RED</span>
7. valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。示例如下:
System.out.println(Color.valueOf("BLUE")); //返回结果: Color.BLUE
8. equals()方法: 比较两个枚举类对象的引用。
2. Enum使用方式
了解了这些基本特性,我们来看看如何使用它们。
1.遍历所有枚举值
知道了有values方法,我们可以轻车熟路地用ForEach循环来遍历了枚举值了。
Color[] colors = Color.values();
for (Color color : colors) {
System.out.print(color + ",");
}
2.在enum中定义方法和变量
比如我们可以为Color增加一个方法随机返回一个颜色。
public enum Color {
Red, Green, Blue;
/**
* 定义一个变量表示枚举值的数目。 (我有点奇怪为什么sun没有给enum直接提供一个size方法).
*/
private static int number = Color.values().length;
/**
* 随机返回一个枚举值 @return a random enum value.
*/
public static Color getRandomColor() {
long random = System.currentTimeMillis() % number;
switch ((int) random) {
case 0:
return Color.Red;
case 1:
return Color.Green;
case 2:
return Color.Blue;
default:
return Color.Red;
}
}
}
可以看出这在枚举类型里定义变量和方法和在普通类里面定义方法和变量没有什么区别。唯一要注意的只是变量和方法定义必须放在所有枚举值定义的后面,否则编译器会给出一个错误。
3.覆载(Override) toString,valueOf方法
前面我们已经知道enum提供了toString,valueOf等方法,很多时候我们都需要覆载默认的toString方法,那么对于enum我们怎么做呢。其实这和覆载一个普通class的toString方法没有什么区别。
public String toString() {
switch (this) {
case Red:
return "Color.Red ";
case Green:
return "Color.Green ";
case Blue:
return "Color.Blue ";
default:
return "Unknow Color ";
}
}
这时我们可以看到,此时再用前面的遍历代码打印出来的是:
Color.Red
Color.Green
Color.Blue
而不是:
Red
Green
Blue
可以看到toString确实是被覆载了。一般来说在覆载toString的时候我们同时也应该覆载valueOf方法,以保持它们相互的一致性。
4.使用构造函数
虽然enum不可以有public的构造函数,但是我们还是可以定义private的构造函数,在enum内部使用。还是用Color这个例子。
public enum Color {
Red("This is Red "), Green("This is Green "), Blue("This is Blue ");
private String desc;
Color(String desc) {
this.desc = desc;
}
public String getDesc() {
return this.desc;
}
}
这里我们为每一个颜色提供了一个说明信息, 然后定义了一个构造函数接受这个说明信息。 要注意这里构造函数不能为public或者protected, 从而保证构造函数只能在内部使用,客户代码不能new一个枚举值的实例出来。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。
5.实现特定的接口
我们已经知道enum可以定义变量和方法,它要实现一个接口也和普通class实现一个接口一样,这里就不作示例了。
6.定义枚举值自己的方法
前面我们看到可以为enum定义一些方法,其实我们甚至可以为每一个枚举值定义方法。这样,我们前面覆载toString的例子可以被改写成这样。
public enum Color {
Red {
public String toString() {
return "Color.Red ";
}
},
Green {
public String toString() {
return "Color.Green ";
}
},
Blue {
public String toString() {
return "Color.Blue ";
}
};
}
从逻辑上来说这样比原先提供一个“全局“的toString方法要清晰一些。
总的来说,enum作为一个全新定义的类型,是希望能够帮助程序员写出的代码更加简单易懂,个人觉得一般也不需要过多的使用enum的一些高级特性,否则就和简单易懂的初衷想违背了。