​java基础 - 枚举

时间:2022-10-10 18:00:00

一、基础用法

枚举类型自动继承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());
}
}
}