网站首页 > 精选教程 正文
第十九章、枚举类型
前言:
- 关键字enum:可以将一组具名的值的有限集合创建为一种新的类型(Class),而这些具名的值可以作为常规的程序组件使用。
- 创建enum时,编译器会为你自动生成一个相关类,此类自动extends java.lang.Enum类。
1. 基本enum特性
Enum类提供的功能如下:
- values() 返回enum实例的数组,而且保持声明的顺序:
- ordinal() 返回一个int值,这是每个enum实例在声明时的次序,从0开始。
- == 来比较enum实例,编译器会自动提供equals和hashCode方法。
- getDeclaringClass() 获取其所属的enum类。
- name() 返回enum实例声明时的名字,与使用toString()效果相同。
- Enum.valueOf() 是在Enum中定义的static方法,他根据给定的名字返回相应的enum实例,如果不存在会抛出异常。
1.1 将静态导入用于enum
- 使用static import能够将enum实例的标识符代入当前的命名空间,所以无需再用enum类型来修饰enum实例。
- 唯一担心的是使用静态导入会不会导致代码令人难以理解。
import static enumerated.Spiciness*;
1.2 向enum中添加新方法
- 除了不能继承自一个enum之外,基本上可以将enum看做一个常规类。
- 也就是说,可以添加方法,甚至可以有main方法。
- 必须先定义enum实例,如果在实例之前定义任何方法或属性,编译时会报错。
- 一旦enum的定义结束,编译器就不允许在使用其构造器来创建任何实例了。
public enum OzWitch {
// Instances must be defined first, before methods:
WEST("Miss Gulch"),
NORTH("Glinda"),
EAST("Wicked"),
SOUTH("Good");//必须在enum实例序列的最后添加一个分号。
private String description;
// Constructor must be package or private access:
private OzWitch(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
@Override
public String toString() {}
public static void main(String[] args) {
for (OzWitch witch : OzWitch.values()) {
print(witch + ": " + witch.getDescription());
}
}
}
2. switch语句中的enum
- 一般来说switch中只能使用整形值,Java SE7开始支持字符串String,也支持enum类型;
- 枚举类型天生就具备整形值的次序,并且可以通过ordinal()方法获取其次序。
enum Signal {
GREEN, YELLOW, RED,
}
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch (color) {
case RED:
case GREEN:
case YELLOW:
}
}
}
3.values()的神秘之处
enum类都自动继承自Enum类(编译器实现),我们可以查看Enum中并没有values()方法。利用反射机制查看究竟:
- values()是由编译器自动添加的static方法。同时创建Explore的过程中,编译器还添加了valueOf()方法。不是Enum类已经有valueOf()方法了吗,不过Enum中的ValueOf()方法需要两个参数,这个新增方法只需一个参数。由于Set只存储方法的名字,不考虑签名,所以removeAll只剩下values。
- 由于values()方法有编译器插入到enum定义中的static方法,所以enum向上转型为Enum,那么values就不可访问了,不过Class中有一个getEnumConstants方法,所以即便Enum接口中没有vlaues方法,仍然可以通过Class对象取得所有enum实例:
enum Search {HITHER, YON}
public class UpcastEnum {
public static void main(String[] args) {
Search[] vals = Search.values();
Enum e = Search.HITHER; // Upcast
// e.values(); // No values() in Enum
for (Enum en : e.getClass().getEnumConstants()) {
System.out.println(en);
}
}
}
getEnumConstants() 获取所有Enum对象的实例
5. 实现,而非继承
- 不能extends:Java不支持多重继承;并编译器自动extends了Enum类了;
- 可以implements:创建一个新的enum,可以同时实现一个或多个接口。
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)];
}
}
6. 随机选取
7. 使用接口组织枚举
- 子类化:implements是enum 子类化的唯一方法。
- 有时希望使用子类将一个enum中的元素进行分组。在一个接口内部创建实现该接口的枚举,以此将元素分组。
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;
}
}
8. 使用EnumSet替代位标志(BitSet)
- Set:是一种集合不能添加重复元素。enum也要求其成员是唯一的。
- EnumSet:Java SE5引入了EnumSet,是为了通过enum创建一种替代品,以替代传统的基于int的“位标志”(BitSet)。这种标志可以用来表示某种开关信息,不过,使用这种标志,最终操作的只是一些bit。
- EnumSet的性能:它在说明一个二进制位是否存在时,具有更好的表达能力,并且无需担心性能。
EnumSet 包含的使用方法:
- EnumSet.noneOf(AlarmPoints.class); 返回Empty set
- EnumSet.complementOf() 用于创建包含与指定的Enum_Set类型相同的元素的EnumSet
- EnumSet.of() 返回参数中添加的Enum元素集合
- EnumSet.range() 返回参数中指定范围的Enum元素
- points.addAll() 添加所有Enum元素
- points.removeAl() 移除参数中包含的Enum元素集合
研究EnumSet文档,会发现of()方法被重载了很多次,不但为可变数量参数进行了重载,而且为接受2至5个显式的参数的情况都进行了重载。这也从侧面表现了EnumSet对性能的关注。
9. 使用EnumMap
- EnumMap:是一种特殊的Map(Key-Value映射表),要求其中的键(key)必须来自于一个enum。
- EnumMap的性能:由于enum本身的限制,所以EnumMap内部是数组实现。因此EnumMap速度很快,可以放心进行查找操作。
- EnumMap的排序:与EnumSet一样,enum实例(key)定义时的次序决定了其在EnumMap中的顺序。
9.1 命令模式(GoF23之一)的具体实现
9.3 EnumMap 包含的使用方法:
- put(k,v) 新增元素(k,v)
- get(k) 返回参数k对应的value
- entrySet() 返回<k,v>实例对象集合
- Map.Entry<K,V>.getValue() 返回实例元素的value
10 常量相关的方法
- 常量相关的方法:constant-specific methods
- 多路分发:multiple dispatching
- 枚举元素:在Enum中定义的元素都是Enum类中的各个实例对象,每个Enum元素都是一个Enum类型的staic final类型对象。
- 常量相关的方法的enum实现方式:enum 允许为每个enum实例(枚举元素)编写方法,从而为每个enum实例赋予各自不同的行为,从而为每个enum实例赋予各自不同的行为。
public enum ConstantSpecificMethod {
DATE_TIME {
String getInfo() {
return DateFormat.getDateInstance().format(new Date());
}
},
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());
}
}
}
10.1 使用enum的职责链
- 职责链模式:(Chain of Responsibility,GoF23设计模式之一):程序员以多种不同的方式来解决一个问题,然后将它们链接在一起。当请求到来时,它遍历这个链,直到这个链中的某个解决方案能够处理此需求。
- 代码示例 参照原文P607
10.2 使用enum的状态机
- 状态机模式:(GoF23设计模式之一):一个状态机可以具有有限个特定的状态,它通常根据输入,从一个状态转移到下个状态,不过也可能存在瞬时状态(transient states),而一旦任务执行结束,状态机会立即离开瞬时状态。
- 瞬时状态:(transient states):
- 代码示例 参照原文P609
11 多路分发
- 单路分发:Java只支持单路分发:如果要执行的操作包含了不只一个类型未知的对象时,java的动态绑定机制只能处理其中一个的类型。
- 多路分发:含二路分发。
多路分发的几种实现方式:
- 使用enum分发:
- 使用常量相关的方法分发
- 使用EnumMap分发
- 使用二维数组
- 上一篇: 枚举类都不知道,还敢说自己会Java?
- 下一篇: Scala基础学习九之枚举和Trait了解
猜你喜欢
- 2024-11-09 Java基础入门要学哪些 怎么掌握反射和枚举
- 2024-11-09 谈谈枚举的新用法--java java枚举类型有什么用
- 2024-11-09 Java面试基础回顾16-枚举 java面试基础知识点
- 2024-11-09 实际工作中推荐使用java枚举类型,提高开发效率#编程
- 2024-11-09 java枚举enumeration java枚举根据value获取key
- 2024-11-09 大年初二来简单聊聊java中枚举类的前世今生
- 2024-11-09 如何用枚举消除if/else?-枚举高阶用法
- 2024-11-09 干货 | 一文搞定Python 枚举 python 枚举遍历
- 2024-11-09 Scala学习九之枚举和Trait了解 枚举compareto
- 2024-11-09 java中的enum第一期:enum存在的意义
你 发表评论:
欢迎- 04-11Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- 04-11Java中你知道几种从字符串中找指定的字符的数量
- 04-11探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- 04-11Python字符串详解与示例(python字符串的常见操作)
- 04-11java正则-取出指定字符串之间的内容
- 04-11String s1 = new String("abc");这句话创建了几个字符串对象?
- 04-11java判断字符串中是否包含某个字符
- 04-11关于java开发中正确的发牌逻辑编写规范
- 最近发表
-
- Java面试“字符串三兄弟”String、StringBuilder、StringBuffer
- Java中你知道几种从字符串中找指定的字符的数量
- 探秘Java面试中问的最多的String、StringBuffer、StringBuilder
- Python字符串详解与示例(python字符串的常见操作)
- java正则-取出指定字符串之间的内容
- String s1 = new String("abc");这句话创建了几个字符串对象?
- java判断字符串中是否包含某个字符
- 关于java开发中正确的发牌逻辑编写规范
- windows、linux如何后台运行jar(并且显示进程名)
- 腾讯大佬私人收藏,GitHub上最受欢迎的100个JAVA库,值得学习
- 标签列表
-
- nginx反向代理 (57)
- nginx日志 (56)
- nginx限制ip访问 (62)
- mac安装nginx (55)
- java和mysql (59)
- java中final (62)
- win10安装java (72)
- java启动参数 (64)
- java链表反转 (64)
- 字符串反转java (72)
- java逻辑运算符 (59)
- java 请求url (65)
- java信号量 (57)
- java定义枚举 (59)
- java字符串压缩 (56)
- java中的反射 (59)
- java 三维数组 (55)
- java插入排序 (68)
- java线程的状态 (62)
- java异步调用 (55)
- java中的异常处理 (62)
- java锁机制 (54)
- java静态内部类 (55)
- java怎么添加图片 (60)
- java 权限框架 (55)
本文暂时没有评论,来添加一个吧(●'◡'●)