Java枚举用法鉴赏参考

190 阅读3分钟

一、认识枚举

JDK1.5引入了新的类型——枚举。在 Java 中它虽然算个“小”功能,却给我的开发带来了“大”方便。

image.png

二、枚举用法

(1)用法1:常量

在JDK1.5 之前,我们定义常量都是: public static fianl.... 。现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法。

public enum Color {  
    RED, GREEN, BLANK, YELLOW;
}  

(2)用法2:switch

JDK1.6之前的switch语句只支持int,char,enum类型,使用枚举,能让我们的代码可读性更强。

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;  
        }
    }
}

详细升级版本:

/** 
 * 季节枚举(不带参数的枚举常量)这个是最简单的枚举使用实例 
 * Ordinal 属性,对应的就是排列顺序,从0开始。 (按照枚举的顺序以此递增)
 */  
private enum SimpleEnum {  
    SPRING,  // ordinal 0
    SUMMER,  // ordinal 1
    AUTUMN,  // ordinal 2
    WINTER;  // ordinal 3
} 

private static void testSwitchCase() {
    String typeName = "f5";
    //这几行注释呢,你可以试着三选一,测试一下效果。
    //String typeName = "firewall";
    //String typeName = "secretMac";
    TypeEnum typeEnum = TypeEnum.fromTypeName(typeName);
    if (typeEnum == null) {
        return;
    }
    switch (typeEnum) {
        case FIREWALL: // case 中我们可以使用下面三种枚举的属性用来做 switch-case 的具体情况。
            System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
            System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
            System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
            break;
        case SECRET:
            System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
            System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
            System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
            break;
        case BALANCE:
            System.out.println("枚举名称(即默认自带的属性 name 的值)是:" + typeEnum.name());
            System.out.println("排序值(默认自带的属性 ordinal 的值)是:" + typeEnum.ordinal());
            System.out.println("枚举的自定义属性 typeName 的值是:" + typeEnum.getTypeName());
            break;
        default:
            System.out.println("default");
    }
}

(3)用法3:向枚举中添加新方法

如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号。而且 Java 要求必须先定义 enum 实例。

  • 获取所有的name;
  • 获取所有的index;
  • 重写 toString()  方法;
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;
    }
    // 普通方法
    public static String getName(int index) {
        for (Color c : Color.values()) {
            if (c.getIndex() == index) {
                return c.name;
            }
        }
        return null;
    }
    // get set 方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;  
    }
    public int getIndex() {
        return index;  
    }
    public void setIndex(int index) {
        this.index = index;
    }
    // 覆盖方法
    @Override
    public String toString() {
        return this.index + "_" + this.name;
    }
    
    // 测试:覆盖方法
    public static void main(String[] args) throws Exception {
        System.out.println(Color.BLANK.toString()); // 3_白色
    }
}

(4)用法4:实现接口

所有的枚举都继承自 java.lang.Enum 类。由于Java 不支持多继承,所以枚举对象不能再继承其他类。

public interface Behaviour {
    void print();
    String getInfo();
}

public enum Color implements Behaviour {
    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 getInfo() {
        return this.name;
    }
    //接口方法
    @Override
    public void print() {
        System.out.println(this.index + ":" + this.name);
    }
} 

(5)用法5:使用接口组织枚举

public interface Food {
    enum Coffee implements Food{ // 咖啡
        BLACK_COFFEE, DECAF_COFFEE, LATTE, CAPPUCCINO;
    }
    enum Dessert implements Food{ // 甜点
        FRUIT, CAKE, GELATO;
    }
}


/** 
 * 测试继承接口的枚举的使用
 */  
private static void testImplementsInterface() {  
    for (Food.DessertEnum dessertEnum : Food.DessertEnum.values()) {  
        System.out.print(dessertEnum + "  ");  
    }  
    System.out.println();
    //我这地方这么写,是因为我在自己测试的时候,把这个coffee单独到一个文件去实现那个food接口,而不是在那个接口的内部。  
    for (CoffeeEnum coffee : CoffeeEnum.values()) {
        System.out.print(coffee + "  ");
    }  
    System.out.println();
    //搞个实现接口,来组织枚举,简单讲,就是分类吧。如果大量使用枚举的话,这么干,在写代码的时候,就很方便调用啦。  
    //还有就是个“多态”的功能吧,  
    Food food = Food.DessertEnum.CAKE; 
    System.out.println(food);
    food = CoffeeEnum.BLACK_COFFEE;
    System.out.println(food);
}

(6)方法6:枚举集合

public class Test {

    enum WeekDayEnum {
        MON, TUE, WED, THU, FRI, SAT, SUN;
    }

    public static void main(String[] args) {
        EnumSet<WeekDayEnum> week = EnumSet.noneOf(WeekDayEnum.class);
        week.add(WeekDayEnum.MON);
        System.out.println("EnumSet中的元素(查看枚举集合的所有元素):" + week);

        week.remove(WeekDayEnum.MON);
        System.out.println("EnumSet中的元素(清空指定枚举元素):" + week);

        week.addAll(EnumSet.complementOf(week));
        System.out.println("EnumSet中的元素(所有元素):" + week);

        // 范围清空的原理? 是枚举中默认的ordinal自动给每个枚举定编号了。所以可以使用范围查询和移除操作
        week.removeAll(EnumSet.range(WeekDayEnum.FRI, WeekDayEnum.SAT));
        System.out.println("EnumSet中的元素(去除周五到周六):" + week);
    }
}

测试结果:

image.png