(转)JDK1.5新特性 (2) - 枚举

2008-04-24 – 9:02 pm

2. 枚举

2.1 枚举的概念及用法

枚举就是定义一个固定的、封闭的值集合。枚举类型的值就是枚举类型的实例。

枚举类型的定义

public enum Priority {High, Medium, Low };

它包括一个关键字enum ,一个新枚举类型的名字 Priority 以及为Priority定义的一组值。

在创建枚举类型时,注意几个重要的概念。

· 所有创建的枚举类型都扩展于 java.lang.Enum. Enum 是在J2SE 5.0 里定义的一个新类, 它本身不是枚举类型.在创建枚举类型时,必须用enum 关键字,不能直接地定义一个继承Enum的类来创建一个枚举类型,尽管所有创建的枚举类型实际上都是Enum 的子类. 如果直接继承Enum, compiler 就会报错(会导致编译错误)。

  • 枚举类型里定义的每一个值都是枚举类型的一个实例, 比方说High是Priority的一个实例.枚举类型又是扩展于Enum. 所以枚举类型的每一个值声明时, 缺省时都将映射到Enum(String name, int ordinal) 构造函数中.换句话说,enum Priority {High, Medium, Low } 的实现是调用了下面的Enum 构造函数:


映射的构造函数调用:

new Enum< Priority >(”High”, 0);

new Enum< Priority >(”Medium”, 1);

new Enum< Priority >(”Low”, 2);

每一个创建的枚举类型都是Enum 的子类,除了上面调用父类 Enum 的构造函数外,枚举类型可以使用参数为定义一些自己的构造函数.当声明值时,只需调用此枚举类型定义的构造函数,而且不必添加 new 关键字。


其它构造函数调用:

enum Priority {

High (38),

Medium(36.5),

Low (5.2);

double temperature;

Priority (double p)

temperature = p;

}

另外要强调的两点: 一是这些枚举类型的构造函数都是私有的.它是不能被其它的类或者其它的枚举类型调用的. 而且这个私有修饰符是由编译器自动加的,如果我们定义这些构造函数时,在前面加上public 修饰符, 就会导致编译错误

  • J2SE 5.0以前,当我们实现一个枚举类时,一般都是把一个整数关联到此枚举类的某一个值的名字,出现的问题是同一个整数可以代表不同枚举类的值. 下面的例子里定义两个枚举类 Course and Grade 如下:

public class Course {

public static final int EnglishLit = 1;

public static final int Calculus = 2;

public static final int MusicTheory = 3;

}

public class Grade {

public static final int A = 1;

public static final int B = 2;

public static final int C = 3;

}

如果开发者误把student1.assignGrade(Grade.A)写成student1.assignGrade(Course.EnglishList); 在编译阶段是不能发现问题的,如果用J2SE 5.0 枚举类型(enum)可以避免这些问题。

  • 枚举类型每一个值都是public, static and final的.也就是说,这些值是唯一的而且一旦定义了是不能被重写或修改.而且尽管在枚举类型每一个值声明时没有出现static关键字, 实际上值都是静态的, 而且我们不能在值前面加上static, public,final 修饰符。
  • 枚举类型都实现了java.lang.Comparable,枚举类型的值是可以比较排序的,排列顺序就是枚举类型定义这些值的顺序.

2.2 枚举类型的应用

for循环中获取枚举类型的所有值

for (Priority g: Priority.values()){

process(g);

}

转换(Switch)

我们常用的一种判断语句就是Switch-case 语句. 在Switch 语句中使用枚举类型,不仅能简化程序,而且增强了程序的可读性.

File1: Task.java

public class Task {

Priority myPriority;

public Task (Priority p) {

myPriority=p;

}

public Priority getPriority(){

return myPriority;

}}

File2: TestSwitch.java

public class TestSwitch (

Task task = new Task(Priority.Medium);

switch (task.getPriority( )) {

case High:

//do case High

break;

case Midum: // fall through to Low

case Low:

//do case Low

break;

default: throw new AssertionError(”Unexpected enumerated value!”);

}

}

J2SE 5.0 的java.util 程序包中提供两个新类:EnumMap 和 EnumSet,这两个类与枚举类型的结合应用可使以前非常繁琐的程序变得简单方便.EnumMap 类提供了java.util.Map 接口的一个特殊实现,该接口中的键(key)是一个枚举类型.

EnumMap 例子

public void test() throws IOException {

EnumMap<Priority, String> descriptionMessages =

new EnumMap< Priority, String>( Priority.class);

descriptionMessages.put(Priority.High, “High means …”);

descriptionMessages.put(Priority.Medium, ” Medium represents…”);

descriptionMessages.put(Priority.Low, ” Low means…”);

for (Priority p : Priority.values( ) ) {

System.out.println(”For priority ” + p + “, decription is: ” +

descriptionMessages.get(p));

}

}

EnumSet 类提供了 java.util.Set 接口的实现,该接口保存了某种枚举类型的值的集合.EnumSet的作用类似于特性的集合,或者类似于某个枚举类型的所有元素的值的子集.EnumSet 类拥有一系列的静态方法,可以用这些方法从枚举类型中获取单个元素或某些元素, 下面的程序例子显示如何这些静态方法:

EnumSet 例子

public class TestEnumSet {

public enum ColorFeature {

RED,BLUE, GREEN, YELLOW,BLACK

} ;

public static void main(String[] args) {

EnumSet allFeatures = EnumSet.allOf(ColorFeature.class);

EnumSet warmColorFeatures = EnumSet.of(ColorFeature.RED,

ColorFeature.YELLOW);

EnumSet non_warmColorFeatures = EnumSet.complementOf(warmColorFeatures);

EnumSet notBlack = EnumSet.range(ColorFeature.RED, ColorFeature.YELLOW);

for (ColorFeature cf : ColorFeature.values()){

if (warmColorFeatures.contains(cf)) {

System.out.println(”warmColor “+cf.name());

}

if (non_warmColorFeatures.contains(cf)) {

System.out.println(”non_WarmColor “+cf.name());

}

}

}

}

枚举类型的函数定义

在介绍创建枚举类型中曾提到枚举类型都是java.lang.Enum的子类. 也就是说, 枚举类型都是可编译的Java 的类,那么就可以在枚举类型里添加构造函数和其它函数

public enum ColorFeature {

RED(0),

BLUE(0),

GREEN(300),

YELLOW(0),

BLACK(0);

/** The degree for each kind of color*/

private int degree;

ColorFeatures(int degree) {

this.degree = degree;

}

public int getDegree( ) {

return degree;

}

public String getDescription( ) {

switch(this) {

case RED: return “the color is red”;

case BLUE: return “the color is blue”;

case GREEN: return “the color is green”;

case BLACK: return “the color is black”;

case YELLOW: return “the color is yellow”

default: return “Unknown Color”;

}

}}

特定于常量的类主体

枚举类型可以定义自己的函数,其实更进一步,枚举类型的每一个值都可以实现枚举类型里定义的抽象函数,这听起来很不可思议,我们可以先看下面的例子.

public enum Priority implements Feature {

High (38) {

public void perform() {

System.out.println(”high 38″);

}

},

Medium(36.5) {

public void perform() {

System.out.println(”medium 36.5″);

}

},

Low (5.2){

public void perform() {

System.out.println(”low 5.2″);

}

};

public abstract void perform();

public String getDescription(Priority p) {

return null;

}

}

枚举类型Priority 定义了一个抽象函数perform(),Priority的每一个值都对perform 函数实现了重载,这就是枚举类型的特定于常量的类主体.在这种情况下,每声明一个值,枚举类型的一个子类生成,然后生成这个子类的唯一的实例来表示这个 值.不同的值,就有对应的不同的子类.每个子类可以对父类的抽象函数进行重载。

public class Task {

Priority myPriority;

public Task (Priority p) {

myPriority=p;

}

public Priority getPriority(){

return myPriority;

}

public void test() throws IOException {

if (myPriority == Priority.High)

System.out.println(Priority.High.getClass().getName());

if (myPriority == Priority.Medium)

System.out.println(Priority.Medium.getClass().getName());

if (myPriority == Priority.Low)

System.out.println(Priority.Low.getClass().getName());

}}

public class TestSwitch {

public static void main(String[] args) {

Task task = new Task(Priority.High);

Task task1 = new Task(Priority.Medium);

Task task2 = new Task(Priority.Low);

try {

task.test();

task1.test();

task2.test();

} catch (IOException e) {

e.printStackTrace();

}

}

Popularity: 6% [?]

Leave a Reply

You must be logged in to post a comment.