Java 枚举类型
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java 枚举类型,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含9784字,纯文字阅读大概需要14分钟。
内容图文
![Java 枚举类型](/upload/InfoBanner/zyjiaocheng/1294/4973a01ae45743328e56d092872372af.jpg)
枚举类型
关键字enum可以将一组具名的值有限集合创建为一种新的类型,而这些具名的值可以作为常规的程序组件使用。
1、基本enum特性
①values()方法返回enum实例的数组,可以遍历enum实例
②ordinal()方法返回一个int值,这是每个enum实例在声明时的次序,从0开始
③getDeclaringClass()方法能够知道其所属的enum类
④name()方法返回enum实例声明时的名字
⑤valueOf()根据给定的名字返回相应的enum实例
⑥Enum类实现了Comparable接口,具有compareTo()方法
⑦Enum类实现了Serializable接口
⑧通过static import可以静态导入其他包中的enum实例,无需再用enum类型来修饰enum实例
2、向enum中添加新方法
在添加新方法时,enum实例序列的最后添加一个分号,并且必须先定义实例。
1
public
enum
OzWitch {
2 WEST("This is west"),
3 NORTH("This is north"),
4 EAST("This is east"),
5 SOUTH("This is south");
6?
7private String description;
8private OzWitch(String description){ this.description = description; }
9public String getDescription(){ return description; }
10?
11 @Override
12public String toString() {
13 String id = name();
14return id + ":" + getDescription();
15 }
16?
17publicstaticvoid main(String[] args) {
18for(OzWitch witch: OzWitch.values())
19 System.out.println(witch);
20 }
21}
22?
23/*Output:
24WEST:This is west
25NORTH:This is north
26EAST:This is east
27SOUTH:This is south
28*/
3、values()方法
Explore[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
Enum[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
对比可知在Enum类中并没有values()方法。通过反编译,可以知道values()方法是由编译器添加的static方法。同时也添加了valueOf()方法,该方法只有一个参数,而在Enum类中的valueOf()方法需要两个参数。
将enum向上转型为Enum就无法访问values()方法,但是在Class中有一个getEnumConstants()方法,通过该方法仍然可以取得所有enum实例。
4、实现接口
所有的enum都继承自java.lang.Enum类。由于Java不支持多重继承,所以enum不能再继承其他,但是可以实现一个或多个接口。
5、随机选取
<T extends Enum<T>>表示T是enum实例。
1
public
class
Enums {
2
private
static Random rand = new Random(47L);
3?
4public Enums() {
5 }
6?
7publicstatic <T extends Enum<T>> T random(Class<T> ec) {
8return (Enum)random((Object[])((Enum[])ec.getEnumConstants()));
9 }
10?
11publicstatic <T> T random(T[] values) {
12return values[rand.nextInt(values.length)];
13 }
14 }
6、使用接口组织枚举
在一个接口内部,创建实现该接口的枚举,以此将元素进行分组。这可以达到将枚举元素分类组织的目的。
当需要与一大堆类型打交道时,接口就不如enum好用了。为了创建一个“枚举的枚举”,可以创建一个新的enum,然后用其实例包装原接口中的每一个enum类。
1
enum
Meal {
2 APPETIZER(Food.Appetizer.class),
3 COFFEE(Food.Coffee.class);
4private Food[] values;
5private Meal(Class<? extends Food> kind) {
6 values = kind.getEnumConstants();
7 }
8publicinterface Food {
9enum Appetizer implements Food {
10 SALAD, SOUP, SPRING_ROLLS;
11 }
12enum Coffee implements Food {
13 BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
14 LATTE, CAPPUCCINO, TEA, HERB_TEA;
15 }
16 }
17public Food randomSelection() {
18return Enums.random(values);
19 }
20 }
7、EnumSet
EnumSet用于替代传统的基于int的“位标志”,这种标志可以用来表示某种“开/关”信息。对同一个参数重复地调用add()方法会被忽略掉。
1
enum
AlarmPoints{START1,START2,LOBBY,OFFICE1,OFFICE2,OFFICE3,BATHROOM}
2
?
3
public
class
EnumSets {
4
public
static
void
main(String[] args) {
5 EnumSet<AlarmPoints> points = EnumSet.noneOf(AlarmPoints.class);//Empty set 6 points.add(AlarmPoints.BATHROOM);
7 System.out.println(points);
8 points.addAll(EnumSet.of(AlarmPoints.OFFICE1,AlarmPoints.OFFICE2,AlarmPoints.OFFICE3));
9 System.out.println(points);
10 points = EnumSet.allOf(AlarmPoints.class);
11 points.removeAll(EnumSet.of(AlarmPoints.START1,AlarmPoints.START2));
12 System.out.println(points);
13 points.removeAll(EnumSet.range(AlarmPoints.OFFICE1,AlarmPoints.OFFICE3));
14 System.out.println(points);
15 points = EnumSet.complementOf(points);//取差集16 System.out.println(points);
17 }
18}
19?
20/*Output:
21[BATHROOM]
22[OFFICE1, OFFICE2, OFFICE3, BATHROOM]
23[LOBBY, OFFICE1, OFFICE2, OFFICE3, BATHROOM]
24[LOBBY, BATHROOM]
25[START1, START2, OFFICE1, OFFICE2, OFFICE3]
26*/
8、EnumMap
EnumMap是一种特殊的Map,它要求其中的键(key)必须来自一个enum。由于enum本身的限制,所以enumMap在内部可由数组实现。
与EnumSet一样,enum实例定义时的次序决定了其在EnumMap中的顺序。enum的每个实例作为一个键,总是存在的。如果没有用put()方法来存入相应值的话,其对应的值就是null。
1
enum
AlarmPoints{START1,START2,LOBBY,OFFICE1,OFFICE2,OFFICE3,BATHROOM}
2
?
3
public
class
EnumMaps {
4
public
static
void
main(String[] args) {
5 EnumMap<AlarmPoints,Command> em =
6new EnumMap<AlarmPoints, Command>(AlarmPoints.class);
7 em.put(AlarmPoints.OFFICE1, new Command() {
8 @Override
9publicvoid action() {
10 System.out.println("This is office1");
11 }
12 });
13 em.put(AlarmPoints.OFFICE2, new Command() {
14 @Override
15publicvoid action() {
16 System.out.println("This is office2");
17 }
18 });
19for(Map.Entry<AlarmPoints,Command> e: em.entrySet()){
20 System.out.print(e.getKey() + ":");
21 e.getValue().action();
22 }
23 }
24}
25?
26interface Command{ void action(); }
27?
28/*Output:
29OFFICE1:This is office1
30OFFICE2:This is office2
31*/
9、常量相关的方法
(1)abstract方法
要实现常量相关的方法,需要为enum定义一个或多个abstract方法,然后为每个enum实例实现该抽象方法。还可以覆盖常量相关的方法。
1
enum
ConstantSpecificMethod{
2
DATE_TIME{
3 String getInfo() { return "Time"; }
4 String f(){ return "Overridden method"; }
5 },
6 CLASSPATH{
7 String getInfo() { return "classpath"; }
8 };
9?
10abstract String getInfo();
11 String f(){ return "default behavior"; }
12?
13publicstaticvoid main(String[] args) {
14for(ConstantSpecificMethod csm: values())
15 System.out.println(csm + ":" + csm.getInfo() + "," + csm.f());
16 }
17}
18?
19/*Output:
20DATE_TIME:Time,Overridden method
21CLASSPATH:classpath,default behavior
22*/
(2)使用enum的职责链
在职责链设计模式中,程序员以多种不同的方式来解决一个问题,然后将它们链接在一起。当一个请求到来时,它遍历这个链,直到链中的某个解决方案能够处理该请求。
src/com/my/chapter19/practice8.java · sumAll/Java编程思想 - 码云 - 开源中国 (gitee.com)
(3)使用enum的状态机
枚举类型非常适合用来创建状态机。一个状态机可以具有有限个特定的状态,它通常根据输入,从一个状态转移到下一个状态,不过也可能存在瞬时状态,而一旦任务执行结束,状态机就会立刻离开瞬时状态。
10、多路分发
如果要执行的操作包含了不止一个类型未知的对象时,需要通过多路分发来解决。要利用多路分发,就必须为每一个类型提供一个实际的方法调用。
(1)使用enum分发
1
enum
Outcome{ WIN,LOSE,DRAW }
2
?
3
interface Competitor<T extends Competitor<T>>{
4 Outcome compete(T competitor);
5}
6?
7class RoShamBo{
8publicstatic <T extends Competitor<T>>
9void match(T a,T b){
10 System.out.println(a + " vs " + b + " :" + a.compete(b));
11 }
12?
13publicstatic <T extends Enum<T> & Competitor<T>>
14void play(Class<T> rsbClass,int size){
15for(int i=0;i<size;i++){
16 match(Enums.random(rsbClass),Enums.random(rsbClass));
17 }
18 }
19}
20?
21publicenum RoShamBo2 implements Competitor<RoShamBo2>{
22 PAPER(Outcome.DRAW,Outcome.LOSE,Outcome.WIN),
23 SCISSORS(Outcome.WIN,Outcome.DRAW,Outcome.LOSE),
24 ROCK(Outcome.LOSE,Outcome.WIN,Outcome.DRAW);
25?
26private Outcome vPAPER,vSCISSORS,vROCK;
27 RoShamBo2(Outcome paper,Outcome scissors,Outcome rock){
28this.vPAPER = paper;
29this.vSCISSORS = scissors;
30this.vROCK = rock;
31 }
32?
33 @Override
34public Outcome compete(RoShamBo2 it) {
35switch (it){
36default:
37case PAPER: return vPAPER;
38case SCISSORS: return vSCISSORS;
39case ROCK: return vROCK;
40 }
41 }
42?
43publicstaticvoid main(String[] args) {
44 RoShamBo.play(RoShamBo2.class,6);
45 }
46}
47?
48/*Output:
49ROCK vs ROCK :DRAW
50SCISSORS vs ROCK :LOSE
51SCISSORS vs ROCK :LOSE
52SCISSORS vs ROCK :LOSE
53PAPER vs SCISSORS :LOSE
54PAPER vs PAPER :DRAW
55*/
(2)使用常量相关的方法
常量相关的方法允许我们为每个enum实例提供方法的不同实现,这可以解决多路分发。
1
public
enum RoShamBo3 implements Competitor<RoShamBo3>{
2 ROCK{
3 @Override
4public Outcome compete(RoShamBo3 opponent) {
5return compete(SCISSORS,opponent);
6 }
7 },
8 SCISSORS{
9 @Override
10public Outcome compete(RoShamBo3 opponent) {
11return compete(PAPER,opponent);
12 }
13 },
14 PAPER{
15 @Override
16public Outcome compete(RoShamBo3 opponent) {
17return compete(ROCK,opponent);
18 }
19 };
20?
21 Outcome compete(RoShamBo3 loser,RoShamBo3 oppoent){
22return ((oppoent == this) ? Outcome.DRAW :
23 ((oppoent == loser) ? Outcome.WIN : Outcome.LOSE));
24 }
25?
26publicstaticvoid main(String[] args) {
27 RoShamBo.play(RoShamBo3.class,6);
28 }
29}
30?
31/*Output:
32PAPER vs PAPER :DRAW
33SCISSORS vs PAPER :WIN
34SCISSORS vs PAPER :WIN
35SCISSORS vs PAPER :WIN
36ROCK vs SCISSORS :WIN
37ROCK vs ROCK :DRAW
38*/
(3)使用EnumMap分发
使用EnumMap能够实现“真正的”两路分发。
1
public
enum RoShamBo4 implements Competitor<RoShamBo4>{
2 PAPER,SCISSORS,ROCK;
3static EnumMap<RoShamBo4,EnumMap<RoShamBo4,Outcome>>
4 table = new EnumMap<RoShamBo4, EnumMap<RoShamBo4, Outcome>>(RoShamBo4.class);
5static {
6for(RoShamBo4 it : RoShamBo4.values()){
7 table.put(it,new EnumMap<RoShamBo4, Outcome>(RoShamBo4.class));
8 }
9 initRow(PAPER,Outcome.DRAW,Outcome.LOSE,Outcome.WIN);
10 initRow(SCISSORS,Outcome.WIN,Outcome.DRAW,Outcome.LOSE);
11 initRow(ROCK,Outcome.LOSE,Outcome.WIN,Outcome.DRAW);
12 }
13staticvoid initRow(RoShamBo4 it,Outcome vPAPER,Outcome vSCISSORS,Outcome vROCK){
14 EnumMap<RoShamBo4,Outcome> row = RoShamBo4.table.get(it);
15 row.put(RoShamBo4.PAPER,vPAPER);
16 row.put(RoShamBo4.SCISSORS,vSCISSORS);
17 row.put(RoShamBo4.ROCK,vROCK);
18 }
19public Outcome compete(RoShamBo4 it){
20return table.get(this).get(it);
21 }
22?
23publicstaticvoid main(String[] args) {
24 RoShamBo.play(RoShamBo4.class,6);
25 }
26}
27?
28/*Output:
29ROCK vs ROCK :DRAW
30SCISSORS vs ROCK :LOSE
31SCISSORS vs ROCK :LOSE
32SCISSORS vs ROCK :LOSE
33PAPER vs SCISSORS :LOSE
34PAPER vs PAPER :DRAW
35*/
(4)使用二维数组
每个enum实例都有一个固定的值(基于其声明的次序),并且可以通过ordinal()方法取得该值。因此我们可以使用二维数组,将竞争者映射到竞争结果。
1
public
enum RoShamBo5 implements Competitor<RoShamBo5>{
2 PAPER,SCISSORS,ROCK;
3privatestatic Outcome[][] table = {
4 {Outcome.DRAW,Outcome.LOSE,Outcome.WIN},//PAPER 5 {Outcome.WIN,Outcome.DRAW,Outcome.LOSE},//SCISSORS 6 {Outcome.LOSE,Outcome.WIN,Outcome.DRAW},//ROCK 7 };
8public Outcome compete(RoShamBo5 other){
9return table[this.ordinal()][other.ordinal()];
10 }
11?
12publicstaticvoid main(String[] args) {
13 RoShamBo.play(RoShamBo5.class,6);
14 }
15}
16?
17/*Output:
18ROCK vs ROCK :DRAW
19SCISSORS vs ROCK :LOSE
20SCISSORS vs ROCK :LOSE
21SCISSORS vs ROCK :LOSE
22PAPER vs SCISSORS :LOSE
23PAPER vs PAPER :DRAW
24*/
参考于《Java编程思想》,第590~619页
原文:https://www.cnblogs.com/yqsumAll/p/15013153.html
内容总结
以上是互联网集市为您收集整理的Java 枚举类型全部内容,希望文章能够帮你解决Java 枚举类型所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。