读Java编程思想随笔の枚举类

  基本enum特性

  创建enum时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum。

 1 enum Shrubbery{
 2         GROUND,CRAWLING,HANGING
 3 }
 4 public class EnumClass {
 5         public static void main(String[] args) {
 6                 for (Shrubbery s:Shrubbery.values()){
 7                         System.out.println(s+" ordinal:"+s.ordinal());
 8                         System.out.println(s.compareTo(Shrubbery.CRAWLING)+" ");
 9                         System.out.println(s.equals(Shrubbery.CRAWLING)+" ");
10                         System.out.println(s==Shrubbery.CRAWLING);
11                         System.out.println(s.getDeclaringClass());
12                         System.out.println(s.name());
13                         System.out.println("--------------------------");
14                 }
15                 for (String s:"HANGING CRAWLING GROUND".split(" ")){
16                         Shrubbery shrub = Enum.valueOf(Shrubbery.class,s);
17                         System.out.println(shrub);
18                 }
19         }
20 }
21 //GROUND ordinal:0
22 //        -1
23 //        false
24 //        false
25 //class com.qiqi.enums.Shrubbery
26 //        GROUND
27 //        --------------------------
28 //        CRAWLING ordinal:1
29 //        0
30 //        true
31 //        true
32 //class com.qiqi.enums.Shrubbery
33 //        CRAWLING
34 //        --------------------------
35 //        HANGING ordinal:2
36 //        1
37 //        false
38 //        false
39 //class com.qiqi.enums.Shrubbery
40 //        HANGING
41 //        --------------------------
42 //        HANGING
43 //        CRAWLING
44 //        GROUND

  ordinal()方法返回一个int值,这是每个enum实例在声明时的次序,从0开始。可以使用==来比较enum实例,编译器会自动为你供equals()和hashcode()方法。Enum类实现了Comparable接口,所以它具有compareTo()方法。同时,它还实现了Serializable接口。如果在enum实例上调用getDeclaringClass方法,我们就知道其所属的enum类。name()方法返回enum实例声明的名字,这与使用toString()方法效果相同。valueOf()是在Enum中定义的static方法,它根据给定的名字返回相应的enum实例,如果不存在给定名字的实例,将会抛出异常。

  静态导入enum

 1 import static com.qiqi.enums.Spiciness.*;//静态导入枚举类
 2 /**
 3 * @ClassName: Burrito
 4 * @Description: 静态导入枚举类
 5 * @Author huhailang
 6 * @Date 2015/12/22 19:58
 7 * @Company 中国奇奇科技有限公司
 8 */
 9 public class Burrito {
10         Spiciness degree;
11         public Burrito(Spiciness degree){
12                 this.degree=degree;
13         }
14 
15         @Override
16         public String toString() {
17                 return "Burrito is "+degree;
18         }
19 
20         public static void main(String[] args) {
21                 System.out.println(new Burrito(NOT));
22                 System.out.println(new Burrito(MEDIUM));
23                 System.out.println(new Burrito(FLAMING));
24         }
25 }
26 //        Burrito is NOT
27 //        Burrito is MEDIUM
28 //     

  向enum中添加新方法

 1 public enum OzWitch {
 2         WEST("miss west"),
 3         NORTH("mis north"),
 4         EAST("miss east"),
 5         SOUTH("miss south");
 6         private String description;
 7         private OzWitch(String description){
 8                 this.description=description;
 9         }
10         public String getDescription(){
11                 return description;
12         }
13 
14         public static void main(String[] args) {
15                 for (OzWitch witch:OzWitch.values()){
16                         System.out.println(witch+":"+witch.getDescription());
17                 }
18         }
19 }
20 //        WEST:miss west
21 //        NORTH:mis north
22 //        EAST:miss east
23 //        SOUTH:miss south

  注意,如果你打算定义自己的方法,那么必须在enum实例序列的最后添加一个分号。同时,Java要求你必须先定义enum实例。如果在定义enum实例之前定义了任何方法或属性,那么在编译时就会得到错误信息。

  enum中的构造器与方法和普通的类没有区别,因为除了少许限制之外,enum就是一个普通的类。

  覆盖enum的方法

 1 public enum SpaceShip {
 2         SCOUT,CARGO,TRANSPORT;
 3 
 4         @Override
 5         public String toString() {
 6                 String id = name();
 7                 String lower = id.substring(1).toLowerCase();
 8                 return id.charAt(0)+lower;
 9         }
10         public static void main(String[] args) {
11              for (SpaceShip s:values()){
12                      System.out.println(s);
13              }
14         }
15 }
16 //        Scout
17 //        Cargo
18 //        Transport

  覆盖enum方法与覆盖普通类方法没有区别。

  switch语句中的enum

 1 enum Signal{
 2         GREEN,YELLOW,RED
 3 }
 4 public class TrafficLight {
 5         Signal color = Signal.RED;
 6         public void change(){
 7                 /**一般情况下,我们必须使用enum类型来修饰一个enum实例,但是case语句中却不必如此*/
 8                 switch (color){
 9                         case RED: color = Signal.GREEN;
10                                 break;
11                         case GREEN:color = Signal.YELLOW;
12                                 break;
13                         case YELLOW:color = Signal.RED;
14                                 break;
15                 }
16         }
17         @Override
18         public String toString() {
19                 return "The traffic light is "+color;
20         }
21 
22         public static void main(String[] args) {
23                 TrafficLight t = new TrafficLight();
24                 for (int i=0;i<7;i++){
25                         System.out.println(t);
26                         t.change();
27                 }
28         }
29 }

  编译器并没有抱怨switch中没有default语句,但这并不是因为每一个Signal都有对应的case语句。如果你注释掉其中的某个case语句,编译器同样不会抱怨什么。这意味着,你必须确保自己覆盖了所有的分支。但是如果在case语句中调用return,那么编译器就会抱怨缺少default语句了。

  探讨values()

 1 enum Explore{
 2         HERE,THREE
 3 }
 4 public class Reflection {
 5         public static Set<String> analyze(Class<?> enumClass){
 6                 System.out.println("Interfaces:");
 7                 for (Type t:enumClass.getGenericInterfaces()){
 8                         System.out.println(t);
 9                 }
10                 System.out.println("Base:"+enumClass.getSuperclass());
11                 System.out.println("Methods:");
12                 Set<String> methods = new TreeSet<String>();
13                 for (Method m:enumClass.getMethods()){
14                         methods.add(m.getName());
15                 }
16                 System.out.println(methods);
17                 return methods;
18         }
19 
20         public static void main(String[] args) {
21                 Set<String> exploreMethods = analyze(Explore.class);
22                 Set<String> enumMethods = analyze(Enum.class);
23                 System.out.println(exploreMethods.containsAll(enumMethods));
24                 System.out.println("Explore.removeAll(Enum):");
25                 exploreMethods.removeAll(enumMethods);
26                 System.out.println(exploreMethods);
27                 //OSExecute.command("javap Explore");
28         }
29 }
30 //        Interfaces:
31 //        Base:class java.lang.Enum
32 //        Methods:
33 //        [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
34 //        Interfaces:
35 //        java.lang.Comparable<E>
36 //        interface java.io.Serializable
37 //        Base:class java.lang.Object
38 //        Methods:
39 //        [compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
40 //        true
41 //        Explore.removeAll(Enum):
42 //        [values]

  我们知道,编译器为你创建的enum类都继承自Enum类。然而,如果你研究一下Enum类就会发现,它并没有values()方法。答案是values()方法是由编译器添加的static方法。可以看出,在创建Explore的过程中,编译器还为其添加了valueOf()方法。这可能有点迷惑,Enum类不是已经有valueOf()方法了吗。不过Enum中valueOf()方法需要两个参数,而这个新增的方法只需一个参数。

 1 enum Search{
 2         HITHER,YON
 3 }
 4 public class UpcastEnum {
 5         public static void main(String[] args) {
 6                 Search [] vals = Search.values();
 7                 Enum e = Search.HITHER;
 8                 /**Enum通过getEnumConstants()取得enum实例*/
 9                 for (Enum en:e.getClass().getEnumConstants()){
10                         System.out.println(en);
11                 }
12         }
13 }
14 //        HITHER
15 //        YON

  enum实例实现多个接口

 1 enum CartoonCharacter implements Generator<CartoonCharacter>{
 2         SLAPPY,SPANKY,PUNCHY,SILLY,BOUNCY,NUTTY,BOB;
 3         private Random rand = new Random(47);
 4         @Override
 5         public CartoonCharacter next() {
 6                 return values()[rand.nextInt(values().length)];
 7         }
 8 }
 9 public class EnumImplementation {
10         public static <T> void printNext(Generator<T> rg){
11                 System.out.println(rg.next()+",");
12         }
13 
14         public static void main(String[] args) {
15                 CartoonCharacter cc = CartoonCharacter.BOB;
16                 for (int i=0;i<10;i++){
17                         printNext(cc);
18                 }
19         }
20 }

  我们已经知道,所有enum都继承自java.lang.Enum类。由于Java不支持多重继承,所以enum不能继承其他类然而,在我们创建一个新的enum时,我们可以同时实现一个或多个接口。

  随机选取

1 public class Enums {
2     private static Random rand = new Random(47);
3     public static <T extends Enum<T>> T random(Class<T> ec) {
4         return random(ec.getEnumConstants());
5     }
6     public static <T> T random(T[] values) {
7         return values[rand.nextInt(values.length)];
8     }
9 } ///:~

  古怪的语法<T extends Enum<T>> 表示T是一个enum实例。而将Class<T>作为参数的话,我们就可以利用Class对象得到enum实例的数组了。重载后的random()方法只需使用T[]作为参数,因为它并不会调用Enum上的任何操作,它只需从数组中随机选择一个元素即可。这样,最终的返回类型正式enum类型。

  Enum只是一个相当短小的类,但是你会发现,它能消除很多冗余的代码。

 1 enum Activity{
 2     SITTING,LYING,STANDING,HOPPING,RUNNING,DODGING,JUMPING,FALLING,FLYING
 3 }
 4 public class RandomTest {
 5     public static void main(String[] args) {
 6         for (int i=0;i<20;i++){
 7             System.out.println(Enums.random(Activity.class)+" ");
 8         }
 9     }
10 }
11 //        STANDING
12 //        FLYING
13 //        RUNNING
14 //        STANDING
15 //        RUNNING
16 //        STANDING
17 //        LYING
18 //        DODGING
19 //        SITTING
20 //        RUNNING
21 //        HOPPING
22 //        HOPPING
23 //        HOPPING
24 //        RUNNING
25 //        STANDING
26 //        LYING
27 //        FALLING
28 //        RUNNING
29 //        FLYING
30 //        LYING

 

posted @ 2015-12-22 21:48  有志竟成  阅读(274)  评论(0)    收藏  举报