关键字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;
}
}
@Override
public 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() { //使用的匿名内部类
@Override
public 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() {//每个实例都赋予不同的行为
return
DateFormat.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();
}
}