JavaBase:枚举类

枚举

提出问题

概述

是什么

关键字enum可以将一组具名的值的有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。

分类,各个分类是什么

为什么要用(作用)

应用场景

  • 多路分发
    • 如果一个系统要分析和执行数学表达式可能会声明Number.plus(Number)等,然而当声明a.plus(b)时,并不知道a或者b的确切类型,则如何让他们进行间交互。

枚举特性

EnumClassMethod

  • Class.values方法,返回enum实例的数组,并且该数组中的元素的严格保持其在enum中声明时的顺序。

可以用来遍历enum实例

1
2
3
4
enum Shrubbery{ GROUND,CRWLING}
public static void main(String[] args){
for(Shrubbery s : Shrubbery.values())
}
  • Enum.valueOf(EnumClass,name)根据给定的名字返回相应的enum实例

EnumObjMethod

  • Obj.ordinal()返回一个int值,是每个enum实例在声明时的次序,从0开始。
  • Obj.name(),返回enum实例声明时的明智,与使用toString方法效果相同

在Enum中添加方法

Enum除了不能继承自一个enum外,基本上可以将enum看作一个常规的类,即可以向enum添加方法。

若打算在枚举中定义方法,则必须在enum实例序列的最后添加一个分号。

switch中的enum

在Java中switch一般只能使用整数,而枚举实例天生具有整数的次序,因此我们可以在switch中使用

1
2
3
switch(color){
case RED:
}

多路分发

当要处理多种交互类型时,程序可能会变得相当混乱。

如果一个系统要分析和执行数学表达式可能会声明Number.plus(Number)等,然而当声明a.plus(b)时,并不知道a或者b的确切类型,则如何让他们进行间交互。

Java只支持单路分发,即如果要执行的操作包含了不止一个类型未知的对象,那么Java的动态绑定机制只能处理其中一个的类型。因此我们必须自己去判定其他的类型,从而实现动态绑定。

解决方法就是多路分发,例如两路分发,就必须有两个方法调用:第一个方法调用决定第一个未知类型,第二个方法决定第二个未知类型。

多态实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public enum Outcome { WIN, LOSE, DRAW }

interface Item {
Outcome compete(Item it);
Outcome eval(Paper p);
Outcome eval(Scissors s);
Outcome eval(Rock r);
}

class Paper implements Item {
public Outcome compete(Item it) { return it.eval(this); }
public Outcome eval(Paper p) { return DRAW; }
public Outcome eval(Scissors s) { return WIN; }
public Outcome eval(Rock r) { return LOSE; }
public String toString() { return "Paper"; }
}

class Scissors implements Item {
public Outcome compete(Item it) { return it.eval(this); }
public Outcome eval(Paper p) { return LOSE; }
public Outcome eval(Scissors s) { return DRAW; }
public Outcome eval(Rock r) { return WIN; }
public String toString() { return "Scissors"; }
}

class Rock implements Item {
public Outcome compete(Item it) { return it.eval(this); }
public Outcome eval(Paper p) { return WIN; }
public Outcome eval(Scissors s) { return LOSE; }
public Outcome eval(Rock r) { return DRAW; }
public String toString() { return "Rock"; }
}

public class RoShamBo1 {
static final int SIZE = 20;
private static Random rand = new Random(47);
public static Item newItem() {
switch(rand.nextInt(3)) {
default:
case 0: return new Scissors();
case 1: return new Paper();
case 2: return new Rock();
}
}
public static void match(Item a, Item b) {
System.out.println(
a + " vs. " + b + ": " + a.compete(b));
}
public static void main(String[] args) {
for(int i = 0; i < SIZE; i++)
match(newItem(), newItem());
}
} /* Output:
Rock vs. Rock: DRAW
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Scissors vs. Scissors: DRAW
Scissors vs. Paper: WIN
Rock vs. Paper: LOSE
Paper vs. Paper: DRAW
Rock vs. Paper: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Rock vs. Scissors: WIN
Rock vs. Paper: LOSE
Paper vs. Rock: WIN
Scissors vs. Paper: WIN
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
Paper vs. Scissors: LOSE
*///:~
  • 第一次分发是在a的compete方法当中,此时根据多态识别了a的具体类型
  • 第二次分发在调用eval方法,此时多态识别了b的类型

使用enum分发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public enum RoShamBo2 implements Competitor<RoShamBo2> {
PAPER(DRAW, LOSE, WIN),
SCISSORS(WIN, DRAW, LOSE),
ROCK(LOSE, WIN, DRAW);
private Outcome vPAPER, vSCISSORS, vROCK;
RoShamBo2(Outcome paper,Outcome scissors,Outcome rock) {
this.vPAPER = paper;
this.vSCISSORS = scissors;
this.vROCK = rock;
}
public Outcome compete(RoShamBo2 it) {
switch(it) {
default:
case PAPER: return vPAPER;
case SCISSORS: return vSCISSORS;
case ROCK: return vROCK;
}
}
public static void main(String[] args) {
RoShamBo.play(RoShamBo2.class, 20);
}
} /* Output:
ROCK vs. ROCK: DRAW
SCISSORS vs. ROCK: LOSE
SCISSORS vs. ROCK: LOSE
SCISSORS vs. ROCK: LOSE
PAPER vs. SCISSORS: LOSE
PAPER vs. PAPER: DRAW
PAPER vs. SCISSORS: LOSE
ROCK vs. SCISSORS: WIN
SCISSORS vs. SCISSORS: DRAW
ROCK vs. SCISSORS: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
ROCK vs. PAPER: LOSE
ROCK vs. SCISSORS: WIN
SCISSORS vs. ROCK: LOSE
PAPER vs. SCISSORS: LOSE
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
SCISSORS vs. PAPER: WIN
*///:~

进阶

反省总结

基础

如何构造一个枚举类

  1. 新建一个Enum的类
  2. 添加枚举的实例,实例的要求:
  • 名称要大写
  • 多个单词是使用下划线进行分割
  • 实例之间使用逗号分割
  • 最后实例结尾使用分号;
  1. 为类添加字段
  2. 必须添加构造方法
  3. 可选:
  • 为字段添加getter和setter
  • 为实例添加doc注释

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public enum SimpleEnum {
/**
* 为枚举添加注释
*/
TEST("1"),
;
/**
* 枚举类需要字段和构造器两个属性,否则会出错
*/
private String code;

public String getCode() {
return code;
}

SimpleEnum(String code) {
this.code = code;
}
}

枚举的作用

管理code或者一些常量

在实际项目当中,会遇到一些状态码的相关东西,这个使用枚举进行维护是相对便捷的

进行switch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 使用switch和枚举类进行结合
*/
public void degree(){
SimpleEnum simpleEnum=SimpleEnum.TEST;
switch (simpleEnum){
case TEST:
System.out.println("test");
return;
case ORDER:
System.out.println("orde");
return;
default:
System.out.println("ss");
}
}

参考