关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用
基本enum特性
创建enum时,编译器会自动的生成一个相关的类,这个类继承与java.lang.Enum,(隐式的)
enum Shrubbery{GROUND,CRAWLING,HANGING}public class EnumClass {public static void main(String[] args) {for (Shrubbery s : Shrubbery.values()) {System.out.println(s + " ordinal " + s.ordinal());//ordinal类似于下标System.out.println(s.compareTo(Shrubbery.CRAWLING) + " ");System.out.println(s.equals(Shrubbery.CRAWLING) + " ");System.out.println(s == Shrubbery.CRAWLING);System.out.println(s.getDeclaringClass());System.out.println(s.name());System.out.println("==================");}for (String s : "HANGING CRAWLING GROUND".split(" ")) {Shrubbery shrubbery = Enum.valueOf(Shrubbery.class,s);//返回具有指定名称的指定enum常量System.out.println(shrubbery);}}}
向enum中添加新方法
enum可以看成一个常规的类,也可以实现接口,可以向其中添加新的方法,设置可以有main方法
public enum OzWitch {WEST("Miss Gulch, aka the Wicked Witch of the West"),NORTH("Glinda, the Good Witch of the North"),EAST("Wicked Witch of the East, wearer of the Ruby " +"Slippers, crushed by Dorothy's house"),SOUTH("Good by inference, but missing");//必须要在实例最后加上分号//必须先定义enum实例,不能再没有定义实例之前定义任何方法或者属性private String description;//只能在内部使用器构造器构建enum实例,构建结束后就不能使用构造器构造任何实例了.private OzWitch(String description) {this.description = description;}public String getDescription() { return description; }public static void main(String[] args) {for(OzWitch witch : OzWitch.values())print(witch + ": " + witch.getDescription());}}
覆盖enum方法
swith语句中的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 GREEN:color = Signal.YELLOW;break;case YELLOW:color = Signal.RED;break;}}@Overridepublic String toString() {return "TrafficLight{" +"color=" + color +'}';}public static void main(String[] args) {final TrafficLight trafficLight = new TrafficLight();for (int i = 0; i < 7; i++) {System.out.println(trafficLight);trafficLight.change();}}}
Values的神秘之处
创建的enum类都继承于Enum类,但是Enum类中并没有values方法
enum Explore{HERE,THERE}public class Reflection {public static Set<String> analyze(Class<?> enumClass){System.out.println("---Analyzing " + enumClass + "---");System.out.println("Interface: ");for (Type t : enumClass.getGenericInterfaces()) {System.out.println(t);}System.out.println("Base : " + enumClass.getSuperclass());System.out.println("Method: ");Set<String> methods = new TreeSet<>();for (Method method : enumClass.getMethods()) {methods.add(method.getName());}System.out.println(methods);return methods;}public static void main(String[] args) {Set<String> exploreMethods = analyze(Explore.class);Set<String> enumMethods = analyze(Enum.class);System.out.println("Explore.containAll(Enum) ? " + exploreMethods.containsAll(enumMethods));System.out.print("Explore.removeAll(Enum): ");exploreMethods.removeAll(enumMethods);System.out.println(exploreMethods);}}
values是由编辑器添加的static方法
Class中有一个getEnumConstants()方法,即便Enum中没有values方法,我们仍然可以通过Class对象取得所有enum实例
enum Search{HITHER,YON}public class UpCastEnum {public static void main(String[] args) {Search[] vals = Search.values();Enum e = Search.HITHER;for (Enum enumConstant : e.getClass().getEnumConstants()) {System.out.println(enumConstant);}}}
getEnumConstants()方法是Class上的方法,也可以对不是枚举的类型调用此方法
public class NonEnum {public static void main(String[] args) {Class<Integer> intClass = int.class;for (Object enumConstant : intClass.getEnumConstants()) {System.out.println(enumConstant);}}}
实现而非继承
enum隐式的继承了Enum,所以不能继承其他的类,但是可以实现接口
enum CartoonCharacter implements Generator<CartoonCharacter> {SLAPPY, SPANKY, PUNCHY, SILLY, BOUNCY, NUTTY, BOB;private Random rand = new Random(47);public CartoonCharacter next() {return values()[rand.nextInt(values().length)];}}public 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);}}
随机选取
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) + " ");}}
使用接口组织枚举
在一个接口的内部创建该接口的枚举,以此将元素分组,可以达到将枚举元素分组的目的
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;}}
对于enum来说实现接口时使其子类化的唯一办法,所以,Food中的每个enum都实现了Food接口,而且可以向上转型为Food
如果要和一堆类型打交道,接口就没有enum好用了,需要先创建一个enum,然后用它的实例包装Food中的每一个enum类
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(); //可以从该class对象中获得某个Food子类中的//所有enum实例}public Food randomSelection() {return Enums.random(values);//随机在菜单中产生菜品}}
public class Meal {public static void main(String[] args) {for (int i = 0; i < 5; i++) {for (Course course : Course.values()) {Food food = course.randomSelection();System.out.println(food);}System.out.println("---");}}}
还有一种更简洁的处理方式,就是将一个enum嵌套在另一个enum中
enum SecurityCategory {STOCK(Security.Stock.class), BOND(Security.Bond.class);Security[] values;SecurityCategory(Class<? extends Security> kind) {//将Security中enum参数作为它的构造器参数values = kind.getEnumConstants();}interface Security {//将其包含的enum组合成一个公共类型enum Stock implements Security {SHORT, LONG, MARGIN}enum Bond implements Security {MUNICIPAL, JUNK}}public Security randomSelection() {return Enums.random(values);}public static void main(String[] args) {for (int i = 0; i < 10; i++) {SecurityCategory category =Enums.random(SecurityCategory.class);System.out.println(category + ": " +category.randomSelection());}}}
使用EnumSet替代标志
EnumSet的设计充分考虑到了速度因素,相比于HashSet而言,非常的快
使用EnumSet的优点:在说明有一个二进制是否存在的时候有更好的表达能力
public enum AlarmPoints {STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,OFFICE4, BATHROOM, UTILITY, KITCHEN}
public class EnumSets {public static void main(String[] args) {EnumSet<AlarmPoints> points =EnumSet.noneOf(AlarmPoints.class); //返回一个枚举类型的空集合points.add(BATHROOM);//添加元素print(points);points.addAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));//添加枚举中的元素print(points);points = EnumSet.allOf(AlarmPoints.class);//添加枚举中所有的元素points.removeAll(EnumSet.of(STAIR1, STAIR2, KITCHEN));print(points);points.removeAll(EnumSet.range(OFFICE1, OFFICE4));//range创建一个enum集,左右都是闭区间,然后再删除print(points);points = EnumSet.complementOf(points);//添加补集元素print(points);}}
使用EnumMap
是一种特殊的Map,它要求其中的键必须是一个enum,由于enum本身的限制,所以EnumMap在内部可以由数组实现,只能将enum的实例作为键来调用put()方法
命令设计模式:
命令模式只需要一个只有单一方法的接口,然后从该接口实现具有各自不同行为的多个子类
public class EnumMaps {public static void main(String[] args) {EnumMap<AlarmPoints, Command> em = new EnumMap<>(AlarmPoints.class);em.put(KITCHEN, new Command() { //使用的匿名内部类@Overridepublic void action() {System.out.println("Kitchen fire");}});em.put(BATHROOM, new Command() {public void action() {print("Bathroom alert!");}});for (Map.Entry<AlarmPoints, Command> e : em.entrySet()) {//循环遍历键值对printnb(e.getKey() + ": ");e.getValue().action();}try {em.get(UTILITY).action();//没有重写方法的会报空指针} catch (Exception e) {print(e);}}}
常量相关的方法
允许为每个enum实例编写方法,从而为没有enum实例赋予不同的行为
public enum ConstantSpecificMethod {DATE_TIME {String getInfo() {//每个实例都赋予不同的行为returnDateFormat.getDateInstance().format(new Date());//获取日期,并且指定了格式为format}},CLASSPATH {String getInfo() {return System.getenv("CLASSPATH");}//获取指定环境变量的值},VERSION {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());}}
public class CarWash {public enum Cycle {UNDERBODY {void action() {print("Spraying the underbody");}},WHEELWASH {void action() {print("Washing the wheels");}},PREWASH {void action() {print("Loosening the dirt");}},BASIC {void action() {print("The basic wash");}},HOTWAX {void action() {print("Applying hot wax");}},RINSE {void action() {print("Rinsing");}},BLOWDRY {void action() {print("Blowing dry");}};abstract void action();}EnumSet<Cycle> cycles =EnumSet.of(Cycle.BASIC, Cycle.RINSE); //相当于基本套餐public void add(Cycle cycle) {cycles.add(cycle);}public void washCar() {for (Cycle c : cycles)c.action();}public String toString() {return cycles.toString();}public static void main(String[] args) {CarWash wash = new CarWash();print(wash);wash.washCar();//基本套餐wash.add(Cycle.BLOWDRY);wash.add(Cycle.BLOWDRY);//增值的服务wash.add(Cycle.RINSE);wash.add(Cycle.HOTWAX);print(wash);wash.washCar();}}
