《Java编程思想》第19章枚举类型
文章目录
19.1 基本enum特性
调用enum
的values()
方法,可以遍历enum
实例。values()
方法返回enum
实例的数组,而且该数组中的元素严格保持其在enum
中声明时的顺序。
创建enum
时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum
。
|
|
ordinal()
方法返回一个int值,这是每个enum
实例在声明时的次序,从0开始。
name()
方法按返回enum
实例声明时的名字,这与使用toString()
方法效果相同。
valueOf()
是在Enum
中定义的static
方法,它根据给定的名字返回相应的enum
实例,如果不存在给定名字的实例,将会抛出异常。
19.1.1 将静态导入用于enum
|
|
19.2 向enum中添加新方法
|
|
如果你打算定义自己的方法,那么必须在emum
实例序列的最后添加一个分号。同时,Java
要求你必须先定义enum
实例。如果在定义enum
实例之前定义了任何方法或属性,那么在编译时就会得到错误信息。
2.1 覆盖enum的方法
|
|
3.Switch语句中的enum
|
|
4.values()的神秘之处
编译器为你创建的enum
类都继承自Enum
类。然而,如果你研究一下Enum
类就会发现,它并没有values()
方法。我们可以利用反射机制编写一个简单的程序,来查看其中的究竟。
|
|
values()
由编译器添加的static
方法。可以看出,在创建Explore
的过程中,编译器还为其添加了valueOf()
方法。这可能有点令人迷惑,Enum
类不会已经有valueOf()
方法了吗。不过Enum
中的valueOf()
方法需要两个参数,而这个新增的方法只需一个参数。由于这里使用的Set
只存储方法的名字,而不考虑方法的签名,所以在调用Explore.removeAll(Enum)
之后,就只剩下[values]
了。
由于values()
方法是由编译器插入到enum
定义中的static
方法,所以,如果你将enum
实例向上转型为Enum
,那么values()
方法就不可访问了。不过,在Class
中有一个getEnumConstants()
方法,所以即便Enum
接口中没有values()
方法,我们仍然可以通过Class
对象取得所有enum
实例:
|
|
因为getEnumConstants()
是Class
上的方法,所以你甚至可以对不是枚举的类调用此方法:
|
|
只不过,此时该方法返回null
,所以当你试图使用其返回的结果时会发生异常。
5.实现,而非继承
所有的enum
都继承自java.lang.Enum
类。由于Java
不支持多重继承,所以你的enum
不能再继承其他类。然而,在我们创建一个新的enum
时,可以同时实现一个或多个接口:
|
|
6.随机选取
|
|
下面是random()
方法的一个简单示例:
|
|
7.使用接口组织枚举
假设你想用enum
来表示不同类型的食物,同时还希望每个enum
元素仍然保持Food
类型。
|
|
对于enum
而言,实现接口是使其自泪花的唯一办法,所以嵌入在Food
中的每个enum
都实现了Food
接口。
|
|
如果你想创建一个“枚举的枚举”,那么可以创建一个新的enum
,然后用其实例包装Food
中的每一个enum
类:
|
|
通过每一个Course
实例中随机地选择一个Food
,我们便能够生成一份菜单:
|
|
还有一种更简洁的管理枚举的办法,就是将一个enum
嵌套在另一个enum
内。
|
|
如果我们将这种方式应用于Food
的例子,结果应该这样:
|
|
8.使用EnumSet替代标志
Java SE5
引入EnumSet
,是为了通过enum
创建一种替代品,以替代传统的基于int
的“位标志”。这种标志可以用来表示某种“开/关”信息。
EnumSet
的设计充分考虑到了速度因素,因为它必须与非常高效的bit
标志相竞争。就其内部而言,它就是将一个long值作为比特向量,所以EnumSet
非常快速高效。使用EnumSet
的优点是,它在说明一个二进制位是否存在时,具有更好的表达能力,并且无须担心性能。
下面的enum
表示在一座大楼中,警报传感器的安放位置:
|
|
然后,我们用EnumSet
来跟踪报警器的状态:
|
|
EnumSet
的基础是long
,一个long
值有64位,而一个enum
实例只需一位bit
表示其是否存在。也就是说,在不超过一个long
的表达能力的情况下,你的EnumSet
可以应用于最多不超过64个元素的enum
。如果enum
超过了64个元素会发生什么呢?
|
|
显然,EnumSet
可以应用于多过64个元素的enum
,所以我猜测,Enum
会在必要的时候增加一个long
。
9.使用EnumMap
EnumMap
是一种特殊的Map
,它要求其中的键必须来自一个enum
。由于enum本身的限制,所以EnumMap
在内部可由数组实现。因此EnumMap
的速度很快,我们可以放心地使用enum
实例在EnumMap
中进行查找操作。不过,我们只能将enum
的实例作为键来调用put()
方法,其他操作与使用一般的Map
差不多。
|
|
与EnumSet
一样,enum
实例定义时的次序决定了其在EnumMap
中声明时的顺序。
10.常量相关的方法
Java
的enum
有一个非常有趣的特性,即它允许程序员为enum
实例编写方法,从而为每个enum
实例赋予各自不同的行为。要实现常量相关的方法,你需要为enum
定义一个或多个abstract
方法,然后为每个enum
实例实现该抽象方法。
|
|
并不能真的将enum
实例作为一个类型来使用:
|
|
|
|
与使用匿名内部类相比较,定义常量相关方法的语法更高效、简洁。
除了实现abstarct
方法以外,程序员是否可以覆盖常量相关的方法呢?答案是肯定的。
|
|
10.1使用enum的职责链
|
|
10.2 使用enum的状态机
|
|
|
|
|
|
11.多路分发
|
|
11.1 使用enum分发
11.2 使用常量相关的方法
11.4 使用二维数组
文章作者 malinkang
上次更新 2013-07-16