目录

一、基础用法

1.1、遍历

1.2、添加方法

1.3、Switch应用

二、枚举的组织

2.1、泛型

2.2、包装器

三、高级用法

3.1、EnumSet

3.2、EnumMap

3.3、常量方法


一、基础用法

        枚举类型自动继承java.lang.Enum。它的ordinal()方法返回一个Int值,指向enum实例在声明时的次序,从0开始。可以使用==来比较enum实例,编译器会自动为你提供equals()和hashCode()方法。Enum类实现了Comparable接口,所以具有compareTo()方法,同时它还实现了Serializable接口。

1.1、遍历

public class EnumClass {
    public static void main(String[] args) {
        //遍历枚举

        /*
        GROUND ordinal: 0 
        -1
        false
        false
        class com.zd.thread.Shrubbery
        GROUND
        */
        for(Shrubbery s : Shrubbery.values()) {
            System.out.println(s + " ordinal: " + s.ordinal()); // 枚举的位置
            System.out.println(s.compareTo(Shrubbery.CRAWLING) + " "); //比较返回-1,0,1
            System.out.println(s.equals(Shrubbery.CRAWLING) + " "); //比较值回bool
            System.out.println(s == Shrubbery.CRAWLING); //如果只有一个值则和equals一样的效果
            System.out.println(s.getDeclaringClass()); //
            System.out.println(s.name());
        }
        System.out.println("----------------------");
        EnumClass.ite();
    }

    public static void ite(){
        for(String s : "HANGING CRAWLING GROUND".split(" ")) {
            Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);//注意valueOf的使用
            System.out.println(shrub); //HANGING CRAWLING GROUND
        }
    }
}
enum Shrubbery { GROUND, CRAWLING, HANGING

1.2、添加方法

        这种写法有两点需要注意:1、构造函数(必须);2、getter方法是可选的,但一般也要写上,不然没法调用

/**
 * @Title: com.zd.thread.GoodsCommandEnum 
 * @Description 这种方式不是太可取,会形成大量的枚举类,建议可以通过接口的方式来实现
 * @author liudong
 * @date 2022-10-10 3:18 p.m.
 */
public enum GoodsCommandEnum {
    Pass("pass", "通过"),
    Hidden("hidden", "隐藏"),
    Delete("delete", "删除"),
    Descend("descend", "降权"),
    Unknown("unknown","未知");

    private String commandName;

    private String btnName;

    GoodsCommandEnum(String commandName, String btnName) {
        this.commandName = commandName;
        this.btnName = btnName;
    }
    //GoodsCommandEnum.Pass.commandCode();
    public String commandCode() {
        return this.commandName;
    }

    //GoodsCommandEnum.Pass.commandName();
    public String commandName(){
        return this.btnName;
    }
}

1.3、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 GREEN:
                color = Signal.YELLOW;
                break;
            case YELLOW:
                color = Signal.RED;
                break;
        }
    }

}

二、枚举的组织

2.1、泛型

        这种用法可以在接口中多定义几个泛型方法,这样就可以实现一个类工厂的效果。在一定程度上可以取代模板方法的设计模式。

//接口定义
public interface Generator<T> {
    T next();
} 

//接口实现,也可以把CartoonCharacter做为一个接口的内部类实现,这样更有利于组织接口
enum CartoonCharacter implements Generator<CartoonCharacter> {
    SLAPPY, SPANKY, PUNCHY, SILLY, BOUNCY, NUTTY, BOB;
    private Random rand = new Random(47);

    @Override
    public CartoonCharacter next() {
        return values()[rand.nextInt(values().length)];
    }
}

class EnumImplementation {
    public static <T> void printNext(Generator<T> rg) {
        System.out.print(rg.next() + ", ");
    }

    public static void main(String[] args) {
        // Choose any instance:
        CartoonCharacter cc = CartoonCharacter.BOB;
        for (int i = 0; i < 10; i++) {
            printNext(cc);
        }

    }
}

实现一个枚举泛型随机器

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 Activity { SITTING, LYING, STANDING, HOPPING,
    RUNNING, DODGING, JUMPING, FALLING, FLYING }

public class RandomTest {
    public static void main(String[] args) {
        for(int i = 0; i < 20; i++)
            System.out.print(Enums.random(Activity.class) + " ");
    }
}

2.2、包装器

2.2.1、接口包装枚举

     这种方法建议用在常量的声明上,因为在实际使用上很少用这种方式实现对象的层次结构。

public interface Food {
    enum Appetizer implements Food {
        SALAD, SOUP, SPRING_ROLLS;
    }
    enum MainCourse implements Food {
        LASAGNE, BURRITO, PAD_THAI,
        LENTILS, HUMMOUS, VINDALOO;
    }
    enum Dessert implements Food {
        TIRAMISU, GELATO, BLACK_FOREST_CAKE,
        FRUIT, CREME_CARAMEL;
    }
    enum Coffee implements Food {
        BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
        LATTE, CAPPUCCINO, TEA, HERB_TEA;
    }
} ///:~

public class TypeOfFood {
    public static void main(String[] args) {
        Food food = Appetizer.SALAD;
        food = MainCourse.LASAGNE;
        food = Dessert.GELATO;
        food = Coffee.CAPPUCCINO;
    }
}

2.2.2、枚举包装枚举

        可以和泛型一起使用,实现简单的类层次结构,也可以用于结构化数据的验证功能。

public enum Course {
    APPETIZER(Food.Appetizer.class),
    MAINCOURSE(Food.MainCourse.class),
    DESSERT(Food.Dessert.class),
    COFFEE(Food.Coffee.class);
    private Food[] values;
    private Course(Class<? extends Food> kind) {
        values = kind.getEnumConstants();
    }
    public Food randomSelection() {
        return Enums.random(values);
    }
}

三、高级用法

3.1、EnumSet

        属于枚举的一个增强功能吧,因为set集合只允许存放值,所以可扩展性不太多。但可以组织多状态值,类似mysql的in的用法。

enum AlarmPoints {
    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
}
public class EnumSets {
    public static void main(String[] args) {
        // Empty set
        EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class);

        //[BATHROOM]
        points.add(BATHROOM);

        //[STAIR1, STAIR2, BATHROOM, KITCHEN]
        points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));
        
        //[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]
        points = EnumSet.allOf(AlarmPoints.class);
        points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));

        //[LOBBY, BATHROOM, UTILITY]
        points.removeAll(EnumSet.range(OFFICE1, OFFICE4));

        //[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]
        points = EnumSet.complementOf(points);
    }
}

3.2、EnumMap

可以实现命令模式。

enum AlarmPoints {
    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
}

interface Command { void action(); }

public class EnumMaps {
    public static void main(String[] args) {
        EnumMap<AlarmPoints,Command> em = new EnumMap<AlarmPoints,Command>(AlarmPoints.class);
        em.put(AlarmPoints.KITCHEN, new Command() {
            @Override
            public void action() {
                System.out.println("Kitchen fire!"); }
        });
        em.put(AlarmPoints.BATHROOM, new Command() {
            @Override
            public void action() { System.out.println("Bathroom alert!"); }
        });

        for(Map.Entry<AlarmPoints,Command> e : em.entrySet()) {
            e.getValue().action();
        }
    }
}

3.3、常量方法

        ENUM允许程序为它的实例编写方法,从而为每个enum实例赋予各不相同的行为。这需要为enum定义一个或多个abstract方法,然后为每个enum实例实现该抽象方法。因为每个枚举值相当于定义的枚举的子类,所以要实现其抽象方法。

public enum ConstantSpecificMethod {
    DATE_TIME {//类为这相当于ConstantSpecificMethod的实例,所以要实现其抽象方法
        @Override
        String getInfo() {
            return DateFormat.getDateInstance().format(new Date());
        }
    },
    CLASSPATH {
        @Override
        String getInfo() {
            return System.getenv("CLASSPATH");
        }
    },
    VERSION {
        @Override
        String getInfo() {
            return System.getProperty("java.version");
        }
    };

    abstract String getInfo();

    public static void main(String[] args) {
        for(ConstantSpecificMethod csm : values()){
            System.out.println(csm.getInfo());
        }
    }
}