`
yunshangbuhe
  • 浏览: 221835 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java枚举类型入门

 
阅读更多
Tiger中的一个重要新特性是枚举构造,它是一种新的Java枚举类型,允许用常量来表示特定的数据片断,而且全部都以类型安全的形式来表示。Tiger 专家、developerWorks 的多产作者 Brett McLaughlin将解释枚举的定义,介绍如何在应用程序中运用枚举,以及它为什么能够让您抛弃所有旧的public static final 代码。

您已经知道,Java 代码的两个基本的构造块是类 和接口。现在 Tiger 又引入了枚举,一般简称它为 enum。这个新类型允许您表示特定的数据点,这些数据点只接受分配时预先定义的值集合。 当然,熟练的程序员可以用静态常量实现这项功能,如清单 1 所示:

清单 1. public static final 的常量

public class OldGrade { 

public static final int A = 1; 
public static final int B = 2; 
public static final int C = 3; 
public static final int D = 4; 
public static final int F = 5; 
public static final int INCOMPLETE = 6; 
}
说明:我要感谢 O'Reilly 媒体公司,该公司允许在本文中使用我撰写的 Java 1.5 Tiger:A Developer's Notebook 一书中“枚举”这一章中的代码示例(请参阅参考资料)。
然后您就可以让类接受像 OldGrade.B 这样的常量,但是在这样做的时候,请记住这类常量是 Java 中 int 类型的常量,这意味着该方法可以接受任何 int 类型的值,即使它和OldGrade 中定的所有级别都不对应。因此,您需要检测上界和下界,在出现无效值的时候,可能还要包含一个 IllegalArgumentException。而且,如果后来又添加另外一个级别(例如OldGrade.WITHDREW_PASSING),那么必须改变所有代码中的上界,才能接受这个新值。

换句话说,在使用这类带有整型常量的类时,该解决方案也许可行,但并不是非常有效。幸运的是,枚举提供了更好的方法。

定义枚举清单 2 使用了一个可以提供与清单 1 相似的功能的枚举:

清单 2. 简单的枚举类型

package com.oreilly.tiger.ch03; 

public enum Grade { 
A, B, C, D, F, INCOMPLETE 
};
在这里,我使用了新的关键字 enum,为 enum 提供了一个名称,并指定了允许的值。然后,Grade 就变成了一个枚举类型,您可以按清单 3 所示的方法使用它:
清单 3. 使用枚举类型

package com.oreilly.tiger.ch03; 

public class Student { 

private String firstName; 
private String lastName; 
private Grade grade; 

public Student(String firstName, String lastName) { 
this.firstName = firstName; 
this.lastName = lastName; 


public void setFirstName(String firstName) { 
this.firstName = firstName; 


public String getFirstName() { 
return firstName; 


public void setLastName(String lastName) { 
this.lastName = lastName; 


public String getLastName() { 
return lastName; 


public String getFullName() { 
return new StringBuffer(firstName) 
.append(" ") 
.append(lastName) 
.toString(); 


public void assignGrade(Grade grade) { 
this.grade = grade; 


public Grade getGrade() { 
return grade; 

}
用以前定义过的类型建立一个新的枚举(grade)之后,您就可以像使用其他成员变量一样使用它了。当然,枚举只能分配枚举值中的一个(例如,A、C 或 INCOMPLETE)。而且,在assignGrade() 中是没有进行错误检测的代码,也没有考虑边界情况,请注意这是如何做到。

使用Java枚举值

迄今为止,您所看到的示例都相当简单,但是枚举类型提供的东西远不止这些。您可以逐个遍历枚举值,也可以在 switch 语句中使用枚举值,枚举是非常有价值的。

遍历Java枚举值

下面我们用一个示例显示如何遍历枚举类型的值。清单 4 所示的这项技术,适用于调试、快速打印任务以及把枚举加载到集合(我很快将谈到)中的工具:

清单 4. 遍历枚举值

public void listGradeValues(PrintStream out) throws IOException { 
for (Grade g : Grade.values()) { 
out.println("Allowed value: '" + g + "'"); 

}
运行这段代码,将得到清单 5 所示的输出:
清单 5. 迭代操作的输出

Allowed Value: 'A' 
Allowed Value: 'B' 
Allowed Value: 'C' 
Allowed Value: 'D' 
Allowed Value: 'F' 
Allowed Value: 'INCOMPLETE'
这里有许多东西。首先,我使用了 Tiger 的新的 for/in 循环(也叫作 foreach 或 增强的 for)。另外,您可以看到 values() 方法返回了一个由独立的 Grade 实例构成的数组,每个数组都有一个枚举类型的值。换句话说,values() 的返回值是 Grade[]。
在枚举间切换

能够在枚举的值之间移动很好,但是更重要的是根据枚举的值进行决策。您当然可以写一堆if (grade.equals(Grade.A)) 类型的语句,但那是在浪费时间。Tiger 能够很方便地把枚举支持添加到过去的好东西 switch 语句上,所以它很容易使用,而且适合您已知的内容。清单 6向将展示如何解决这个难题:

清单 6. 在枚举之间切换

public void testSwitchStatement(PrintStream out) throws IOException { 
StringBuffer outputText = new StringBuffer(student1.getFullName()); 

switch (student1.getGrade()) { 
case A: 
outputText.append(" excelled with a grade of A"); 
break; 
case B: // fall through to C 
case C: 
outputText.append(" passed with a grade of ") 
.append(student1.getGrade().toString()); 
break; 
case D: // fall through to F 
case F: 
outputText.append(" failed with a grade of ") 
.append(student1.getGrade().toString()); 
break; 
case INCOMPLETE: 
outputText.append(" did not complete the class."); 
break; 


out.println(outputText.toString()); 
}
在这里,枚举值被传递到 switch 语句中(请记住,getGrade() 是作为 Grade 的实例返回的),而每个 case 子句将处理一个特定的值。该值在提供时没有枚举前缀,这意味着不用将代码写成 case Grade.A,只需将其写成 case A 即可。如果您不这么做,编译器不会接受有前缀的值。

现在,您应该已经了解使用 switch 语句时的基本语法,但是还有一些事情您需要知道。在使用 switch 之前进行计划正如您所期待的,在使用枚举和 switch 时,您可以使用 default 语句。清单 7 显示了这个用法:

清单 7. 添加一个 default 块

public void testSwitchStatement(PrintStream out) throws IOException { 
StringBuffer outputText = new StringBuffer(student1.getFullName()); 

switch (student1.getGrade()) { 
case A: 
outputText.append(" excelled with a grade of A"); 
break; 
case B: // fall through to C 
case C: 
outputText.append(" passed with a grade of ") 
.append(student1.getGrade().toString()); 
break; 
case D: // fall through to F 
case F: 
outputText.append(" failed with a grade of ") 
.append(student1.getGrade().toString()); 
break; 
case INCOMPLETE: 
outputText.append(" did not complete the class."); 
break; 
default: 
outputText.append(" has a grade of ") 
.append(student1.getGrade().toString()); 
break; 


out.println(outputText.toString()); 
}
研究以上代码可以看出,任何没有被 case 语句处理的枚举值都会被 default 语句处理。这项技术您应当坚持采用。原因是:假设 Grade 枚举被您的小组中其他程序员修改(而且他忘记告诉您这件事)成清单 8 所示的版本:

清单 8. 给 Grade 枚举添加一个值

package com.oreilly.tiger.ch03; 

public enum Grade { 
A, B, C, D, F, INCOMPLETE, 
WITHDREW_PASSING, WITHDREW_FAILING 
};
现在,如果使用清单 6 的代码所示的新版 Grade,那么这两个新值会被忽略。更糟的是,您甚至看不到错误!在这种情况下,存在某种能够通用的 default 语句是非常重要的。清单 7 无法很好地处理这些值,但是它会提示您还有其他值,您需要处理这些值。一旦完成处理,您就会有一个继续运行的应用程序,而且它不会忽略这些值,甚至还会指导您下一步的动作。所以这是一个良好的编码习惯。
枚举和集合您所熟悉的使用 public static final 方法进行编码的那些东西,可能已经转而采用枚举的值作为映射的键。如果您不知道其中的含义,请参见清单 9,它是一个公共错误信息的示例,在使用 Ant 的 build 文件时,可能会弹出这样的消息,如下所示:

清单 9. Ant 状态码

package com.oreilly.tiger.ch03; 

public enum AntStatus { 
INITIALIZING, 
COMPILING, 
COPYING, 
JARRING, 
ZIPPING, 
DONE, 
ERROR 
}
为每个状态码分配一些人们能读懂的错误信息,从而允许人们在 Ant 提供某个代码时查找合适的错误信息,将这些信息显示在控制台上。这是映射(Map)的一个绝好用例,在这里,每个映射(Map)的键都是一个枚举值,而每个值都是键的错误信息。清单 10 演示了该映射的工作方式:
清单 10. 枚举的映射(Map)

public void testEnumMap(PrintStream out) throws IOException { 
// Create a map with the key and a String message 
EnumMap antMessages = 
new EnumMap(AntStatus.class); 

// Initialize the map 
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."); 

// Iterate and print messages 
for (AntStatus status : AntStatus.values() ) { 
out.println("For status " + status + ", message is: " + 
antMessages.get(status)); 

}
该代码使用了泛型(generics)(请参阅参考资料)和新的 EnumMap 构造来建立新映射。而且,枚举值是通过其 Class 对象提供的,同时提供的还有映射值的类型(在该例中,它只是一个简单的字符串)。该方法的输出如清单 11 所示:
Java枚举类型中的 Class 对象您可能已经注意到,清单 10 中的示例代码实际上表明 Tiger 把枚举当作类,这可以从AntStatus 的 Class 对象那里得到证明,该对象不仅可用,而且正被实际使用。这是真的。归根到底, Tiger 还是把枚举看成是特殊的类类型。有关枚举的具体实现细节,请参阅Java 5.0 Tiger: A Developer's Notebook 的第三章(请参阅参考资料)。

清单 11. 清单 10 的输出

[echo] Running AntStatusTester... 
[java] For status INITIALIZING, message is: Initializing Ant... 
[java] For status COMPILING, message is: Compiling Java classes... 
[java] For status COPYING, message is: Copying files... 
[java] For status JARRING, message is: JARring up files... 
[java] For status ZIPPING, message is: ZIPping up files... 
[java] For status DONE, message is: Build complete. 
[java] For status ERROR, message is: Error occurred.
更进一步枚举也可以与集合结合使用,而且非常像新的 EnumMap 构造,Tiger 提供了一套新的EnumSet实现,允许您使用位操作符。另外,可以为枚举添加方法,用它们实现接口,定义叫作特定值的类的实体,在该实体中,特定的代码被附加到枚举的具体值上。这些特性超出了本文的范围,但是在其他地方,有详细介绍它们的文档(请参阅参考资料)。

使用Java枚举类型,但是不要滥用

学习任何新版语言的一个危险就是疯狂使用新的语法结构。如果这样做,那么您的代码就会突然之间有 80% 是泛型、标注和枚举。所以,应当只在适合使用枚举的地方才使用它。那么,枚举在什么地方适用呢?一条普遍规则是,任何使用常量的地方,例如目前用 switch代码切换常量的地方。如果只有单独一个值(例如,鞋的最大尺寸,或者笼子中能装猴子的最大数目),则还是把这个任务留给常量吧。但是,如果定义了一组值,而这些值中的任何一个都可以用于特定的数据类型,那么将枚举用在这个地方最适合不过。


转自:http://developer.51cto.com/art/200906/131627.htm
分享到:
评论

相关推荐

    mybatis入门实战之枚举类型

    本项目为mybatis实战二之枚举类型,里面有简单的demo,适合初学者下载运行,能对mybatis的typehandler有一个初始的认识和运用

    Java JDBC简单入门之枚举(Enum)、泛型、反射、JDBC整合

    采用java 应用程序的方式搭建简单的jdbc项目,JDBC简单入门之枚举(Enum)、泛型、反射、JDBC整合

    Java初学者入门教学

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    java2入门经典.part01

    java2入门经典.part01 Java2入门经典 图书目录 译者序 序 前言 第一章:Java概述 什么是Java Java语言的特性 学习Java java程序 学习Java要走的路 ava环境 基于Java语言的面向对象程序设计 对象是什么 如何定义...

    java 编程入门思考

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    实验12 单例模式与枚举.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员...本专栏主要为Java入门者提供实验参考。

    Java2入门经典.rar

    译者序 序 前言 第一章:Java概述 什么是Java Java语言的特性 学习Java ava程序 学习Java要走的路 ava环境 基于Java语言的面向对象...有固定序列整型值的变量(枚举) 布尔型变量 运算符的优先级 程序注释 本章小结 ……

    Java语言程序设计教程(Java 7)——入门与提高篇05

    第5章对编码能力提升,包括异常处理、输入输出、集合框架、正则表达式、枚举类型和Annotation。异常处理,对程序中可能出现的异常情况进行处理;输入输出,对输入输出流和文件操作进行介绍;集合框架,介绍泛型与...

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt 完整版 Java初级教程 Java语言程序设计 第3章 运算符、表达式、语句(共16页).ppt 完整版 Java初级教程 Java语言程序设计 第4...

    java经典编程300例

    Java经典编程300例》内容包括java语言概述、eclipse开发工具、java语言基础、流程控制、数组及其常用操作、面向对象入门、面向对象进阶、字符串与包装类、java集合类框架、常用数学工具类、错误处理、输入/输出、...

    完整版 Java初级教程 Java语言程序设计 全套PPT课件资源集合 共8个章节 含各类辅导资料.rar

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt 完整版 Java初级教程 Java语言程序设计 第3章 运算符、表达式、语句(共16页).ppt 完整版 Java初级教程 Java语言程序设计 第4...

    java集合-EnumSet的使用

    EnumSet 是 Java 中用于存储枚举类型元素的集合类。它是 AbstractSet 的子类,并专门为枚举类型设计,提供了高效的实现。 下面是关于 EnumSet 的一些重要信息: 存储枚举元素:EnumSet 只能存储同一个枚举类型的...

    JAVA经典编程300例

    Java经典编程300例》内容包括java语言概述、eclipse开发工具、java语言基础、流程控制、数组及其常用操作、面向对象入门、面向对象进阶、字符串与包装类、java集合类框架、常用数学工具类、错误处理、输入/输出、...

    Java实验7 序列化.doc

    本专栏主要为Java程序设计(基础)实验报告和Java程序设计(进阶)实验报告,基础篇有JAVA环境搭建、Java语言基础、方法和数组、面向对象基础、Java常用类、继承与接口、成员...本专栏主要为Java入门者提供实验参考。

    Java核心编程技术源码

    Java高级特性:反射、泛型、注释符、自动装箱和拆箱、枚举类、可变参数、可变返回类型、增强循环、静态导入。随书附赠光盘内容为《Java高手真经(编程基础卷):Java核心编程技术》各种原型包、系统源程序。《Java高手...

    Java经典编程300例(完整版+源码

    枚举类型与泛型、 swing入门、 多线程、 网络通信和数据库操作。 本书所精选的实例都是一线开发人员在实际项目中所积累的,并进行了技术上的解析,给出了详细的实现过程。读者通过对本书的学习,能够提高开发的能力...

    完整版 Java初级教程 Java语言程序设计 第7章 Java中的常用类(共14页).ppt

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt 完整版 Java初级教程 Java语言程序设计 第3章 运算符、表达式、语句(共16页).ppt 完整版 Java初级教程 Java语言程序设计 第4...

    完整版 Java初级教程 Java语言程序设计 第4章 类和对象(共22页).ppt

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt 完整版 Java初级教程 Java语言程序设计 第3章 运算符、表达式、语句(共16页).ppt 完整版 Java初级教程 Java语言程序设计 第4...

    完整版 Java初级教程 Java语言程序设计 第8章 集合框架(共19页).ppt

    完整版 Java初级教程 Java语言程序设计 第2章 基本数据类型、数组和枚举(共19页).ppt 完整版 Java初级教程 Java语言程序设计 第3章 运算符、表达式、语句(共16页).ppt 完整版 Java初级教程 Java语言程序设计 第4...

Global site tag (gtag.js) - Google Analytics