JDK 1.6引入了枚举这个重要的特性,现在就来谈谈枚举类的常见用法。
1.使用枚举的原因:简洁性
比如我们在定义颜色类的时候,我们往往需要知道这里面的具体内容并且对里面的成员做一个辅助性的说明,在正常情况下我们会这样做:
abstract class TestC {
public static final TestC Red = new TestC() {
public String toString() {
return "红色";
}
};
public static final TestC GREEN = new TestC() {
public String toString() {
return "绿色";
}
};
public static final TestC WHITE = new TestC() {
public String toString() {
return "白色";
}
};
public static final TestC YELLOW = new TestC() {
public String toString() {
return "黄色";
}
};
public abstract String toString();
}
可以看到这样代码有很多地方是相似的,并且阅读起来也很费时,而JAVA枚举类就为我们提供了一个比较方便的操作途径,为了实现上面的功能,我们可以采取以下做法:
public class Test {
public enum Color {
RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
// 成员变量
private String name;
private int index;
// 构造方法
private Color(String name, int index) {
this.name = name;
this.index = index;
}
// 覆盖方法
@Override
public String toString() {
return this.index + "_" + this.name;
}
}
public static void main(String[] args) {
System.out.println(Color.RED.name);
System.out.println(Color.RED.index);
System.out.println(Color.RED.toString());
}
}
这两段代码的可读性立马就可以看出来,并且我们不断做了辅助性说明,还表明了各种颜色的序号,由此可见枚举类的作用。
(1)枚举类中常用方法:
toString()方法,显示枚举类元素,上例中对这个方法进行了覆盖,如果不覆盖它的话一般打印变量名
valueOf(String arg0)方法,通过传入的arg0字符串解析出一个该枚举类的实例,其中传入的字符串必须是元素列表的名称之一,否则将抛出 java.lang.IllegalArgumentException异常,在web应用中这个方法作用很重要。该方法为静态方法,不需创建实例即可使用,如通过Test.valueOf("RED")即可返回Member实例
values()方法,返回一个该枚举类的数组,其中数组的元素即为该枚举类中元素列表中的元素
ordinal()方法,返回枚举元素实例中元素列表中的位置,起始位置为0。如Test.WHITE.ordinal()的结果为2
name()方法,默认情况下返回元素实列的变量名,该方法为final不可覆盖的.
(2)枚举需要注意的地方:
枚举元素列表必须写在枚举类的最前面,每个元素之间用逗号隔开,元素列表结束位置后若没有其他内容,则可以不写分号,否则必须要写。
枚举类中所有的构造器是private的,外部程序不能够创建枚举类的实例。枚举类中可以显式的指明调用哪个构建器,如MEMBER和MEMBER()这两种元素列表声明是等价的,都是调用默认的构建器,而MEMBER("普通会员")则是显式的指明程序调用第二个构建器.
枚举类可以有抽象方法,但必须在元素列表声明中实现这些方法。此外,枚举类中还可以声明一些普通的成员变量和方法,如上例所示
enum都是继承java.lang.Enum的。
2.枚举类的常见用法
用法一:用于switch分支结构:
enum Signal {
GREEN, YELLOW, RED
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
color = Signal.GREEN;
break;
case YELLOW:
color = Signal.RED;
break;
case GREEN:
color = Signal.YELLOW;
break;
}
}
}
用法二: 如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。
而且 Java 要求必须先定义 enum 实例。最初的例子已经说明了如何添加新方法。
用法三:随机选取
首先利用泛型定义一个一般的随机类,后面就可以利用这个类对Enum实例进行随机选择。
import java.util.*;
import java.lang.*;
public class Enums{
private static Random rand=new Random(47);
public static <T extends Enum<T>> T random(Class<T> ec){
return random(ec.getEnumConstants());
}
public static <T> T random(T[] values){
return values[rand.nextInt(values.length)];
}
}
接下来我们可以可以进行测试,如下:
enum Color { RED, GREEN, WHITE, YELLOW }
class RandomTest{
public static void main(String []args){
for(int i=0;i<15;i++)
System.out.print(Enums.random(Color.class)+" ");
}
}
用法四:使用接口分组织枚举
我们无法从enum继承子类,但是很多时候我们需要扩张enum中的元素,这个时候,我们可以通过创建一个接口,然后在接口内部,创建该接口的枚举,达到将枚举元素分类组织的目的。例如我们想用enum来表示不同类别的失误,同时希望每个enum仍然保持Food类型,我们可以这么实现:
public interface Food{
enum Appetizer implements Food{
SALAD,SOUP,SPRING_ROLLS;
}
enum MainCourse implements Food{
LENTILS,HUMMOUS,PAD_THAI,VINDALOD;
}
enum Dessert implements Food{
FRUIT,CAKE,TIRAMISU;
}
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,TEA;
}
}
同时我们可以进一步进行枚举的嵌套,对于这个例子,我们进一步完善,可以看到如下的例子:
import java.util.*;
public enum Meal2{
APPETIZER(Food.Appetizer.class),
MAINCOURSE(Food.MainCourse.class),
DESSERT(Food.Dessert.class),
COFFEE(Food.Coffee.class);
private Food[] values;
private Meal2(Class <? extends Food> kind){
//EnumConstants可以从该Class对象中去的某个Food子类的所有Enum实例
values=kind.getEnumConstants();
}
public interface Food{
enum Appetizer implements Food{
SALAD,SOUP,SPRING_ROLLS;
}
enum MainCourse implements Food{
LENTILS,HUMMOUS,PAD_THAI,VINDALOD;
}
enum Dessert implements Food{
FRUIT,CAKE,TIRAMISU;
}
enum Coffee implements Food{
BLACK_COFFEE,DECAF_COFFEE,TEA;
}
}
public Food randomSelection(){
return Enums.random(values);
}
//测试
public static void main(String []args){
for(int i=0;i<4;i++){
for(Meal2 meal:Meal2.values()){
Food food=meal.randomSelection();
System.out.println(food);
}
System.out.println("-----------------------");
}
}
}
关于枚举,就说这么多吧