第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的职责链¶
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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
10.2 使用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 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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 | |