枚举
tiger(JDK1.5)的新特性,简称为enum,这个新特性允许我们表示特定的数据点(这些数据点只接受分配时预先定义的值集合)。
通过使用新的enum
关键字创建指定的对象集合,您可以创建一个枚举类型。然后,可以将每个指定的值看作是那个类的一个实例,这为您提供了指定的整数集合所无法提供的编译时类型安全。
我在一个博客上看到有个作者这样说(挺有意思):奉天呈运,Tiger昭曰:Enum将是经过命名的常量,而不再是一堆令人困惑的整数,钦此(不得不说这句话概括的很好)。
在使用enum
关键字创建新的枚举类型时,实际上是在创建java.lang.Enum
类的子类。
枚举类型的每一个值都将映射到protectedEnum(String name, int ordinal)
构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了每个设置的优先值。
为什么是protected呢?因为Enum构造函数一般都不是由new间接调用的,而是使用enum关键字时,将创建Enum子类。
enum Size {Small, Medium, Large}
编译为:
new Enum<Size>("Small", 0);
new Enum<Size>("Medium", 1);
new Enum<Size>("Large", 2);
解读
Enum<Eextends Enum<E>>
我翻到api
中对
Enum
的定义,吓我一跳,没看懂
public abstract class Enum<E extends Enum<E>>
implements Comparable<E>, Serializable {
private final String name;
private final int ordinal;
public final String name() {
return name;
}
public final int ordinal() {
return ordinal;
}
protected Enum(String name, int ordinal) {
this.name = name;
this.ordinal = ordinal;
}
…… ……
…… ……
}
看了几篇文章后总算是有些明白了:
-
Enum接受一个类型参数
-
Enum是一个抽象类,任何Enum的子类都必须为Enum提供一个类型参数
-
这个类型参数必须是Enum的子类
为什么java.lang.Enum被声明为Enum<EextendsEnum<E>>?
-
类型参数E被使用为getDeclaringClass()的返回值
-
类型参数E作为compareTo()的参数
OpType opType = OpType.ADD;
ProductStatus status =ProductStatus.NORMAl;
opType.compareTo(status); // 这样子编译时就会报错
再比如:
Rank r = Rank.ACE;
Suit s = Suit.HEART;
r.compareTo(s); // syntax error, argument must be of type Rank
Rank z = Enum.valueOf(Rank.class, "TWO");
枚举可以遍历,枚举类.values()方法(这是枚举类型的方法)返回了一个由独立的枚举类实例构成的数组。
特定于常量类主体
这个东西刚开始看可不太好理解,特定于常量的类主体是enum
关键字的一个受支持的特性;这个概念正在深入到将枚举类型的每个元素作为一个子类对待的领域。
我们来看一个实例分析
public class Sample3 {
enum Size { // Size相当与java.lang.Enum的一个子类
Small {
public double getPricingFactor() {
return 0.8;
}//发现假如枚举常量的类主体中有getPricingFactor()方法而,Size没有这个方法,这样是不行的,没有办法调用到
},// 可以在Size中写一个abstract的getPricingFactor()方法(常量类主体实现),本例不是abstractor,说明常量的类主体中是重写
Medium,
Large,
ExtraLarge {
public double getPricingFactor() {
return 1.2;
}
},
ExtraExtraLarge {
public double getPricingFactor() {
return 1.2;
}
};
public double getPricingFactor() {
return 1.0;
}
}
public static void main(String args[]) {
for (Size s : Size.values()) {
System.out.println(s.getClass().toString());
System.out.println(s.getDeclaringClass().toString());
double d = s.getPricingFactor();
System.out.println(s + " Size has pricing factor of " + d);
System.out.println();
}
}
}
运行结果:
class test.Sample3$Size$1 // getClass()的结果
class test.Sample3$Size // getDeclaringClass()的结果
Small Size has pricing factor of 0.8
class test.Sample3$Size
class test.Sample3$Size
Medium Size has pricing factor of 1.0
class test.Sample3$Size
class test.Sample3$Size
Large Size has pricing factor of 1.0
class test.Sample3$Size$2
class test.Sample3$Size
ExtraLarge Size has pricing factor of 1.2
class test.Sample3$Size$3
class test.Sample3$Size
ExtraExtraLarge Size has pricing factor of 1.2
分析:
当一个枚举中的一个实例他有自己的类主体时,我们用getClass()获取得到的是结果显示为Size的子类并且用一个整数表示。为什么getDeclaringClass()的结果就还会是Size呢?来看一下
/* Enum.class */
public final Class<E> getDeclaringClass() {
Class clazz = getClass();
Class zuper = clazz.getSuperclass();
return (zuper == Enum.class) ? clazz : zuper; // 关键在这里
}
枚举与集合
java.util
程序包中包含两个类:EnumMap
和EnumSet
,这两个类有助于使处理枚举类型变得更容易一些。EnumMap
类提供了java.util.Map
接口的一个特殊实现,该接口中的键(key)是一个枚举类型。EnumSet
类提供了java.util.Set
接口的实现,该接口保存了某种枚举类型的值的集合。
实例:
public class EnumMapSample {
enum Size{
Small,
Medium,
Large;
}
public static void main(String[] args) {
Map<Size, Double> map=new EnumMap<Size,Double>(Size.class);
map.put(Size.Small, 0.8);
map.put(Size.Medium, 1.0);
map.put(Size.Large, 1.2);
for(Map.Entry<Size, Double> entry : map.entrySet()){
helper(entry);
}
}
public static void helper(Map.Entry<Size, Double> entry){
System.out.println("Map entry:"+entry);
System.out.println(entry.getKey().getClass());
}
}
运行结果:
Map entry:Small=0.8
class test.EnumMapSample$Size
Map entry:Medium=1.0
class test.EnumMapSample$Size
Map entry:Large=1.2
class test.EnumMapSample$Size
总结
使用枚举类型的基本概念很简单。您可以先定义一个指定的、封闭的值集合。然后,在需要这些值中的某一个值时,可以通过它的名称来指定它。该名称携带为其设置的类型。对于不同的大小,不是说1= Small, 2 = Medium, 3 = Large
参考资料:
-
BrettMcLaughlin的文章《枚举类型快速入门》
-
xangd翻译的一篇文章《深入浅出J2SE5.0枚举类型(akaEnum<E extends Enum<E>>) 》不过好像原文本身就存在一些错误。