JDK5.0新特性之:枚举
文/陈刚 2005-11-09
一、前言
JDK5.0出来有快一年了吧,泛泛的浏览过一些资料,不知道是文章写得生涩,还是我愚笨,总之是没太明白。反正所做的项目也没有用到,所以放在了一边。近来公司平台升级到JBOSS4和JDK5,看来要仔佃看它一看看。上网搜索了一些资料,花了两小时阅读,算明白了一些,好象也不是很难。现将心得和理解结集成文,以便后来者。
JDK5.0主要有哪些新特性呢?如下列表
- 泛型
- 增强的for循环
- 自动装箱和自动拆箱
- 类型安全的枚举
- 可变长度参数
- 静态引入
- 元数据(注解)
- C风格的格式化输出
本文先讲“类型安全的枚举”。
二、旧的历史
举个例:有一个如下的“花(flower)”类,它有一个颜色(color)属性,用int型来表示其颜色。
public class Flower {
private int color;
public void setColor(int color) {
this.color = color;
}
public int getColor(){
return color;
}
}
这时一般我们会创建一个常量类,来存放颜色常量,如下:
public interface Color {
int RED = 0;
int BLACK = 1;
int YELLOW = 2;
int BLUE = 3;
int WHITE = 4;
int ORANGE = 5;
}
以后我们用的时候就可以这样:
public class Client {
public static void main(String[] args) {
Flower f = new Flower();
f.setColor(Color.RED);
}
}
Color类就是一个我们自己来实现的枚举类,当然它并不是严格意义上的枚举类,而且JDK5.0之前还没有枚举。这时会出现一个问题:setColor参数是int型,那么也许用户会不小心用一个非法的int值赋进去,这样就可能产生BUG,如:f.setColor(100);显示100并非是我们设定中的颜色值。
在那本有名的java著作<<Effective java>> Joshua Bloch,用了专门的一章(第5章)来讨论这个问题,书中给出了一个比较严谨的解决方案,如下代码所示
(1)用Color类更改如下:
public class Color {
private final int color;
private Color(int color) {
this.color = color;
}
public int getColorValue() {
return color;
}
public static final Color RED = new Color(0);
public static final Color BLACK = new Color(1);
public static final Color YELLOW = new Color(2);
public static final Color BLUE = new Color(3);
public static final Color WHITE = new Color(4);
public static final Color ORANGE = new Color(5);
}
(2)Flower类也要相应的更改,将int改为Color型。
public class Flower {
private Color color;
public void setColor(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}
(3)客户端Client不用修改。
这样Flower类的setColor方法就只接收Color,也不用担心用户不心传入非法的参数值了。
三、新的特性:JDK5.0枚举
(1)简单的例子
JDK5.0的枚举,正好可以解决上面我们讨论的问题,而且更简洁。还是用上面的代码做示例,只需要将Color类修改如下,Flower、Client都无法更改。
public enum Color {
RED, BLACK, YELLOW, BLUE, WHITE, ORANGE
}
很简单吧。接下来我们做更深一步的说明:
- 所有枚举类都是java.lang.Enum的子类(JDK内核自动将Color隐性继承自Enum)
- RED...ORANGE都是Color的实例对象
上面的Color枚举类,功能好象还和以前的例子不完全一样,我们再次修改如下。
public enum Color {
RED(0), BLACK(1), YELLOW(2), BLUE(3), WHITE(4), ORANGE(5);
int color;
Color(int color){
this.color=color;
}
public int getColorValue(){
return color;
}
}
从这里我们可以看到枚举类是如何创建构造函数及方法的,有一些隐性的东西要说明一下:
- 枚举类的构造函数要求是private的,如果象例子里那样不加修饰符,则Java会自动给加上。但如果你想加上public则会报错。
- RED(0), BLACK(1)...等枚举值必须定义在前面,而且最后一个枚举值ORANGE(5);未尾用分号结束。
(2)在循环中使用枚举类
枚举类都有一个values方法可以得到它值的数组:Color[] colors=Color.values();而且枚举类都支持泛型(以后的文章会重点说到),所以我们可以这样来遍历这个数组:
Color[] colors = Color.values();
for (Color c : colors) {
System.out.println("color value=" + c.getColorValue());
}
更简洁的写法是这样:
for (Color c : Color.values()) {
System.out.println("color value=" + c.getColorValue());
}
(3)在switch(分支)中使用枚举
如下代码示例,这里要注意将“case RED:”写成“case Color.RED:”是会报错的,因为JDK5.0可以自动根据“switch (color)”就判断入你要使用什么枚举类型了。从这里也可以看出JDK5.0确实为用户做了帖心的考虑,尽量让程序员少写代码,写更简单的代码。
Color color = Color.RED;
switch (color) {
case RED:
//process ...
break;
case BLACK:
//process ...
break;
case WHITE:
//process ...
break;
default:
//process ...
}
(4)JDK5.0新增的集合:EnumMap 和EnumSet
给出两个例子,一切尽在不言中了。(说明:这两个例子用到了JDK5.0中泛型的知识)
Map<Color, String> map = new EnumMap<Color, String>(Color.class);
map.put(Color.RED, "红色");
map.put(Color.BLACK, "黑色");
map.put(Color.WHITE, "白色");
for (Color c : Color.values()) {
System.out.println(c + " chinese is: " + map.get(c));
}
Set all = EnumSet.allOf(Color.class);
EnumSet warmColors = EnumSet.of(Color.RED, Color.YELLOW);
Set notWarmColors = EnumSet.complementOf(warmColors);
Set notBlack = EnumSet.range(Color.RED, Color.YELLOW);
四、参考资料
http://dev.yesky.com/451/2044451_1.shtml
五、作者简介
陈刚,广西桂林人,著作有《Eclipse从入门到精通》
您可以通过其博客了解更多信息和文章:http://www.ChenGang.com.cn