|
| 1 | +# 枚举类型 |
| 2 | + |
| 3 | +`Java 5` 包含对枚举类型的支持。 这是一个简单的例子: |
| 4 | + |
| 5 | +```java |
| 6 | + enum Season { WINTER, SPRING, SUMMER, FALL } |
| 7 | +``` |
| 8 | + |
| 9 | +每个枚举类型声明都可以以程式化的方式扩展为相应的类。相应的类被设计为每个枚举常量都有一个实例,绑定到一个合适的静态最终变量。 例如,上面的枚举声明扩展为一个名为 `Season` 的类。 这个类存在四个实例,绑定到四个静态最终变量,名称分别为 `WINTER`,`SPRING`,`SUMMER`,和 `FALL`. |
| 10 | + |
| 11 | +与枚举类型对应的每个类都是 `java.lang.Enum` 的子类。 它在 `Java` 文档中的定义是这样开始的: |
| 12 | + |
| 13 | +```java |
| 14 | + class Enum<E extends Enum<E>> |
| 15 | +``` |
| 16 | + |
| 17 | +你可能会发现这种可怕的一见钟情 - 我们当然都这么做! 但不要恐慌。实际上,我们已经看到了类似的东西。 令人担忧的短语 `E extends Enum <E>` 与我们在 `max` 定义中遇到的 `T extends Comparable <T>` 很像(见 `3.2` 节),我们将看到它们出于相关原因。 |
| 18 | + |
| 19 | +为了理解发生了什么,我们需要看看代码。 例 `3-4` 显示了基类 `Enum`,例 `3-5` 显示了与上面的枚举类型声明对应的类 `Season`。(`Enum` 的代码遵循 `Java` 库中的源代码,但我们简化了几个要点。) |
| 20 | + |
| 21 | +这是 `Enum` 类声明的第一行: |
| 22 | + |
| 23 | +```java |
| 24 | + public abstract class Enum<E extends Enum<E>> implements Comparable<E> |
| 25 | +``` |
| 26 | + |
| 27 | +下面是季节课的声明的第一行: |
| 28 | + |
| 29 | +```java |
| 30 | +class Season extends Enum<Season> |
| 31 | +``` |
| 32 | + |
| 33 | +例3-3。比较 |
| 34 | + |
| 35 | +```java |
| 36 | + class Comparators { |
| 37 | + public static <T> T max(Collection<? extends T> coll, Comparator<? super T> cmp){ |
| 38 | + T candidate = coll.iterator().next(); |
| 39 | + for (T elt : coll) { |
| 40 | + if (cmp.compare(candidate, elt) < 0) { candidate = elt; } |
| 41 | + } |
| 42 | + return candidate; |
| 43 | + } |
| 44 | + public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll){ |
| 45 | + return max(coll, Comparators.<T>naturalOrder()); |
| 46 | + } |
| 47 | + public static <T> T min(Collection<? extends T> coll, Comparator<? super T> cmp){ |
| 48 | + return max(coll, reverseOrder(cmp)); |
| 49 | + } |
| 50 | + public static <T extends Comparable<? super T>> T min(Collection<? extends T> coll){ |
| 51 | + return max(coll, Comparators.<T>reverseOrder()); |
| 52 | + } |
| 53 | + public static <T extends Comparable<? super T>> Comparator<T> naturalOrder(){ |
| 54 | + return new Comparator<T>() { |
| 55 | + public int compare(T o1, T o2) { return o1.compareTo(o2); } |
| 56 | + }; |
| 57 | + } |
| 58 | + public static <T> Comparator<T> reverseOrder(final Comparator<T> cmp){ |
| 59 | + return new Comparator<T>() { |
| 60 | + public int compare(T o1, T o2) { return cmp.compare(o2,o1); } |
| 61 | + }; |
| 62 | + } |
| 63 | + public static <T extends Comparable<? super T>> Comparator<T> reverseOrder(){ |
| 64 | + return new Comparator<T>() { |
| 65 | + public int compare(T o1, T o2) { return o2.compareTo(o1); } |
| 66 | + }; |
| 67 | + } |
| 68 | + } |
| 69 | +``` |
| 70 | + |
| 71 | +例3-4。 枚举类型的基类 |
| 72 | + |
| 73 | +```java |
| 74 | + public abstract class Enum<E extends Enum<E>> implements Comparable<E> { |
| 75 | + private final String name; |
| 76 | + private final int ordinal; |
| 77 | + protected Enum(String name, int ordinal) { |
| 78 | + this.name = name; this.ordinal = ordinal; |
| 79 | + } |
| 80 | + public final String name() { return name; } |
| 81 | + public final int ordinal() { return ordinal; } |
| 82 | + public String toString() { return name; } |
| 83 | + public final int compareTo(E o) { |
| 84 | + return ordinal - o.ordinal; |
| 85 | + } |
| 86 | + } |
| 87 | +``` |
| 88 | + |
| 89 | +例3-5。 对应于枚举类型的类 |
| 90 | + |
| 91 | +```java |
| 92 | + // corresponds to |
| 93 | + // enum Season { WINTER, SPRING, SUMMER, FALL } |
| 94 | + final class Season extends Enum<Season> { |
| 95 | + private Season(String name, int ordinal) { super(name,ordinal); } |
| 96 | + public static final Season WINTER = new Season("WINTER",0); |
| 97 | + public static final Season SPRING = new Season("SPRING",1); |
| 98 | + public static final Season SUMMER = new Season("SUMMER",2); |
| 99 | + public static final Season FALL = new Season("FALL",3); |
| 100 | + private static final Season[] VALUES = { WINTER, SPRING, SUMMER, FALL }; |
| 101 | + public static Season[] values() { return VALUES.clone(); } |
| 102 | + public static Season valueOf(String name) { |
| 103 | + for (Season e : VALUES) if (e.name().equals(name)) return e; |
| 104 | + throw new IllegalArgumentException(); |
| 105 | + } |
| 106 | + } |
| 107 | +``` |
| 108 | + |
| 109 | +匹配的东西,我们可以开始看到这是如何工作的。 类型变量 `E` 表示 `Enum` 的子类,它实现了一个特定的枚举类型,比如 `Season`。每个 `E` 必须满足: |
| 110 | + |
| 111 | +```java |
| 112 | + E extends Enum<E> |
| 113 | +``` |
| 114 | + |
| 115 | +所以我们可以把 `E` 作为 `Season`,因为: |
| 116 | + |
| 117 | +```java |
| 118 | + Season extends Enum<Season> |
| 119 | +``` |
| 120 | + |
| 121 | +此外,`Enum` 的声明告诉我们: |
| 122 | + |
| 123 | +```java |
| 124 | + Enum<E> implements Comparable<E> |
| 125 | +``` |
| 126 | + |
| 127 | +所以它是这样的: |
| 128 | + |
| 129 | +```java |
| 130 | + Enum<Season> implements Comparable<Season> |
| 131 | +``` |
| 132 | + |
| 133 | +因此,我们可以将 `Season` 类型的两个值相互比较,但我们无法将季节类型的值与任何其他类型的值进行比较。 |
| 134 | + |
| 135 | +没有类型变量,`Enum` 类的声明就会像这样开始: |
| 136 | + |
| 137 | +```java |
| 138 | + class Enum implements Comparable<Enum> |
| 139 | +``` |
| 140 | + |
| 141 | +而 `Season` 类的声明将如下开始: |
| 142 | + |
| 143 | +```java |
| 144 | + class Season extends Enum |
| 145 | +``` |
| 146 | + |
| 147 | +这更简单,但它太简单了。 有了这个定义,`Season` 将实现 `Comparable <Enum>` 而不是 `Comparable<Season>`,这意味着我们可以将 `Season` 类型的值与任何枚举类型的值进行比较,这肯定不是我们想要的! |
| 148 | + |
| 149 | +一般来说,当你想精确地确定类型时,像 `T` 这样的模式经常出现 `Comparable <T>` 和 `E extends Enum <E>`。当我们查看战略和主题观察者设计模式时,我们会看到更多的例子,参见第 `9.4` 节和第 `9.5` 节。 |
| 150 | + |
| 151 | +定义的其余部分是 `Joshua Bloch` 在 `Effective Java(Addison-Wesley)` 中描述的类型安全模式的一个简单应用,后者又是 `Gamma`,`Helm`,`Johnson` 和 `Vlissides` 在设计模式中描述的单例模式的一个实例(`Addison-Wesley`出版社)。 |
| 152 | + |
| 153 | +基类 `Enum` 定义了两个字段,一个字符串名称和一个整数序号,它们由枚举类型的每个实例拥有;这些字段是最终的,因为一旦它们被初始化,它们的值永远不会改变。该类的构造函数是受保护的,以确保它仅在此类的子类中使用。每个枚举类都使构造函数保持私有,以确保它仅用于创建枚举常量。例如,`Season` 类有一个私人构造函数,它被调用四次以初始化最终变量 `WINTER`,`SPRING`,`SUMMER` 和 `FALL`。 |
| 154 | + |
| 155 | +基类为名称和序号字段定义访问器方法。该 `toString` 方法返回名称,并且 `compareTo` 方法仅返回两个枚举值的序数的差异。(与第 `3.1` 节中的 `Integer` 定义不同,这是安全的,因为不存在溢出的可能性)。因此,常量与它们的序号具有相同的顺序 - 例如,`WINTER` 在 `SUMMER` 之前。 |
| 156 | + |
| 157 | +最后,每个类中有两个对应于枚举类型的静态方法。 `values` 方法返回该类型所有常量的数组。它返回内部数组的一个(浅)克隆。克隆对于确保客户端无法更改内部阵列至关重要。请注意,调用 `clone` 方法时不需要强制转换,因为克隆数组现在可以利用协变返回类型(请参见第 `3.8` 节)。 `valueOf` 方法接受一个字符串并返回相应的常量,通过搜索内部数组找到。如果字符串没有命名枚举值,它将返回 `IllegalArgumentException`。 |
| 158 | + |
| 159 | + |
| 160 | + |
| 161 | + |
| 162 | + |
| 163 | + |
| 164 | + |
| 165 | + |
| 166 | + |
| 167 | + |
| 168 | + |
| 169 | + |
| 170 | + |
| 171 | + |
| 172 | + |
| 173 | + |
| 174 | + |
| 175 | + |
| 176 | + |
| 177 | + |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | + |
| 184 | + |
| 185 | + |
| 186 | + |
| 187 | + |
| 188 | + |
| 189 | + |
| 190 | + |
| 191 | + |
| 192 | + |
| 193 | + |
| 194 | + |
| 195 | + |
| 196 | + |
| 197 | + |
| 198 | + |
| 199 | + |
| 200 | + |
| 201 | + |
| 202 | + |
| 203 | + |
| 204 | + |
| 205 | + |
| 206 | + |
| 207 | + |
| 208 | + |
| 209 | + |
| 210 | + |
| 211 | + |
| 212 | + |
| 213 | + |
| 214 | + |
| 215 | + |
| 216 | + |
| 217 | + |
| 218 | + |
| 219 | + |
| 220 | + |
| 221 | + |
| 222 | + |
| 223 | + |
| 224 | + |
| 225 | + |
| 226 | + |
| 227 | + |
| 228 | + |
| 229 | + |
| 230 | + |
| 231 | + |
| 232 | + |
| 233 | + |
| 234 | + |
| 235 | + |
| 236 | + |
| 237 | + |
| 238 | + |
| 239 | + |
| 240 | + |
| 241 | + |
| 242 | + |
| 243 | + |
| 244 | + |
| 245 | + |
| 246 | + |
| 247 | + |
| 248 | + |
| 249 | + |
| 250 | + |
| 251 | + |
| 252 | + |
| 253 | + |
| 254 | + |
| 255 | + |
| 256 | + |
| 257 | + |
| 258 | + |
| 259 | + |
| 260 | + |
| 261 | + |
| 262 | + |
| 263 | + |
| 264 | + |
| 265 | + |
| 266 | + |
| 267 | + |
| 268 | + |
| 269 | + |
| 270 | + |
| 271 | + |
0 commit comments