Archive

Posts Tagged ‘Enumerated Types enum’

java特性-枚举

March 28th, 2008 No comments

2 Enumerated Types
2.1 创建enum
创建enum类型必须包括至少3个基本成分
A:enum关键字
B:enum类的名字
C:一组该类的值
一些其他可定义的成分
D:一些enum要实现的接口
E:变量定义
F:方法定义
G:特殊的赋值

看一下代码:

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
  public enum Grade {
     A, B, C, D, F, INCOMPLETE
  }
 
  public class Student {
      private String name;
      private Grade  grade;
      public Student(String name){
          this.name = name;
      }
      public void setName(String name) {
          this.name = name;
      }
      public String getName() {
          return name;
      }
      public void assignGrade(Grade grade) {
          this.grade = grade;
      }
      public Grade getGrade() {
          return grade;
      }
      /**
       * @param args
       */
      public static void main(String[] args) {
          Student studentA = new Student("A");
          Student studentB = new Student("B");
          Student studentC = new Student("C");
          studentA.assignGrade(Grade.B);
          studentB.assignGrade(Grade.INCOMPLETE);
          studentC.assignGrade(Grade.A);
      }
  }

注意:
A:你可以把所有的public static final的变量在enum类中声明
B:大部分时候,你只需要使用enum的基本功能
C:按照约定用大写字符定义你的enum
D:enum类像一般的class类被引用
以下是enum的基本概念:
A:enum是类
B:所有的enum类都继承java.lang.Enum
C:enum类中定义的值不是integer,而是一个java.lang.Enum的实例
D:enum类没有公有的构造器,这是为了防止创建新的值
E:enum类中的所有值都是public static final的(Enums are not “final” when they have value-specific methods)
F:enum的值可以用=或或者equasl()来计较
G:enum类都实现了java.lang.Comparable
H:enum类override toString()方法,返回类中value的name,如Grade.INCOMPLETE.toString()返回”INCOMPLETE”,toString()方法不是fianl,你可以override
I:enum类提供一个valueOf()方法,如Grade.valueOf(“INCOMPLETE”)返回Grade.INCOMPLETE
J:enum类提供一个final的方法ordinal(),返回整形的各enum值在enum类中的位置,从0开始
K:enum类提供values()方法,返回enum类中enum值的集合

2.2 Declaring Enums Inline
看一下代码

1
2
3
4
5
   public class Downloader {
      public enum DownloadStatus { INITIALIZING, IN_PROGRESS, COMPLETE };
       .
       .
   }

需要说明的是申明DownloadStatus就不需要再用static修饰了

2.3 Switching on Enums
看一下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    public static void switchStatement(Student student) {
        switch (student.getGrade()) {
            case A:
                break;
            case B:
                break;
            case C:
                break;
            case D:
                break;
            case F:
                break;
            case INCOMPLETE:
                break;
            default:
                break;
        }
    }

需要注意的是在这里case A而不是case Grade.A;这里只是为了简化写法,和static import没有关系
switch语句最好加上default处理,说不定有人会修改enum类,这样你的switch语句还是可以处理unknown conditions

2.4 Maps of Enums
看一下以前的写法

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
    public static final int INITIALIZING = 0;
    public static final int COMPILING    = 1;
    public static final int COPYING      = 2;
    public static final int JARRING      = 3;
    public static final int ZIPPING      = 4;
    public static final int DONE         = 5;
    public static final int ERROR        = 6;
 
    public static String[] antMessages = new String[] {
            "Initalizing Ant...",        // INITIALIZING
            "Compiling Java classes...", // COMPILING
            "Copying files...",          // COPYING
            "JARring up files...",       // JARRING
            "ZIPping up files...",       // ZIPPING
            "Build complete.",           // DONE
            "Error occurred."            // ERROR
                                         };
 
    public static void main(String[] args) {
        .
        .
        int antStatus = antProcess.getStatus();
        System.out.println("ant> " + antMessages[antStatus]);
        .
    }

使用EnumMap的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
    public enum AntStatus {
        INITIALIZING, COMPILING, COPYING, JARRING, ZIPPING, DONE, ERROR
    }
 
    import java.util.EnumMap;
    public class AntEnumMap {
        /**
         * @param args
         */
        public static void main(String[] args) {
            EnumMap antMessages = new EnumMap(AntStatus.class);
            antMessages.put(AntStatus.INITIALIZING, "Initializing Ant...");
            antMessages.put(AntStatus.COMPILING, "Compiling Java classes...");
            antMessages.put(AntStatus.COPYING, "Copying files...");
            antMessages.put(AntStatus.JARRING, "JARring up files...");
            antMessages.put(AntStatus.ZIPPING, "ZIPping up files...");
            antMessages.put(AntStatus.DONE, "Build complete.");
            antMessages.put(AntStatus.ERROR, "Error occurred.");
            for (AntStatus status : AntStatus.values()) {
                System.out.println("For status " + status + ", message is: " + antMessages.get(status));
            }
        }
    }

附件的好处是初始化EnumMap的时候不需要排序,保证enums对应message的正确性
感觉优化不是很明显,还是那么多代码要写;在创建EnumMap对象的时候如果可以写成new EnumMap(AntStatus.class,String[] strings)从而在内部完成map的装载是不是更方便?

2.5 Sets of Enums
看一下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
  public enum GuitarFeatures {
      ROSEWOOD, // back/sides
      MAHOGANY, // back/sides
      ZIRICOTE, // back/sides
 
      SPRUCE, // top
      CEDAR,  // top
 
      AB_ROSETTE,    // abalone rosette
      AB_TOP_BORDER, // abalone top border
 
      IL_DIAMONDS, // diamond/square inlay
      IL_DOTS      // dots inlays
  }

import java.util.EnumSet;

1
2
3
4
5
6
7
8
9
10
11
12
13
  public class GuitarEnumSet {
      public static void main(String[] args) {
          EnumSet allFeatures = EnumSet.allOf(GuitarFeatures.class);
          EnumSet backSides = EnumSet.of(GuitarFeatures.ROSEWOOD,
                                         GuitarFeatures.MAHOGANY,
                                         GuitarFeatures.ZIRICOTE);
          EnumSet bourgeoisD150 = EnumSet.of(GuitarFeatures.ROSEWOOD,
                                             GuitarFeatures.SPRUCE,
                                             GuitarFeatures.AB_ROSETTE,
                                             GuitarFeatures.IL_DIAMONDS);
          boolean hasAbRosette = bourgeoisD150.contains(GuitarFeatures.AB_ROSETTE);
      }
  }

详细看一下api

2.6 Adding Methods to an Enum
看一下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
  public enum GuitarFeatures {
      ROSEWOOD(0),        // back/sides
      MAHOGANY(0),        // back/sides
      ZIRICOTE(300),      // back/sides
      SPRUCE(0),          // top
      CEDAR(0),           // top
      AB_ROSETTE(75),     // abalone rosette
      AB_TOP_BORDER(400), // abalone top border
      IL_DIAMONDS(150),   // diamond/square inlay
      IL_DOTS(0);         // dots inlays
 
      private float upcharge;
 
      GuitarFeatures(float upcharge){
          this.upcharge = upcharge;
      }
 
      public float getUpcharge() {
          return upcharge;
      }
  }

为enum类添加了带float参数构造方法,类中的每个枚举值的声明都要将使用此构造方法;枚举值的定义以分号结束;变量upcharge的申明不能放到枚举值的申明之前;枚举类的构造方法是私有的,不能申明为public

2.7 Implementing Interfaces with Enums
首先构造一个interface类

1
2
3
  public interface Features {
    public float getUpcharge();
  }

修改enum类的定义为:

1
2
3
4
 public enum GuitarFeatures implements Features {
  .
  .
 }

2.8 Value-Specific Class Bodies
看一下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
  enum Opcode {
    PUSH(1) {
      public void perform(StackMachine machine, int[] operands) {
        machine.push(operands[0]);
      }
    },
 
    ADD(0) {
      public void perform(StackMachine machine, int[] operands) {
        machine.push(machine.pop( ) + machine.pop( ));
      }
    },
 
    BEZ(1) {
      public void perform(StackMachine machine, int[] operands) {
        if (machine.pop( ) == 0) machine.setPC(operands[0]);
      }
    };
 
    Opcode(int numOperands) { this.numOperands = numOperands; }
    int numOperands;
    public abstract void perform(StackMachine machine, int[] operands);
  }

之前说过enum都是final的,除了在Value-Specific Class Bodies的情况下,实事上,上面的编码看,每个enum value都创建了一个匿名子类,编译后,除了enum类本身外,多了几个enum value的子类,又从反编译class文件看到一般的enum类都会被声明为final,而这里没有.
以上的写法往往在debug时很麻烦,以前在debug ejb代码的时候也是碰到,系统会帮你生成一些非代码级的代码调用,看一下简单的实现:

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
  enum Opcode {
      PUSH(1), ADD(0), BEZ(1);
 
      int numOperands;
 
      Opcode(int numOperands){
          this.numOperands = numOperands;
      }
 
      public void perform(StackMachine machine, int[] operands) {
          switch (this) {
              case PUSH:
                  machine.push(operands[0]);
                  break;
              case ADD:
                  machine.push(machine.pop() + machine.pop());
                  break;
              case BEZ:
                  if (machine.pop() == 0) machine.setPC(operands[0]);
                  break;
              default:
                  throw new AssertionError();
          }
      }
  }