本章主要介绍在使用枚举和注解这两种类型时要注意的问题。
本条主要是讲枚举类型enum的优缺点。 ### int常量为什么不好? 枚举类型还不存在之前(JDK1.5才引入枚举类型),大多数程序都使用下面的int常量形式代替枚举:
public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
它的缺点如下: - 没有类型安全可言,即使误传了编译器也不会给予任何警告 - 没有自己的命名空间,导致不同的枚举类型必须加上前缀区分,比如上面的APPLE_
就是前缀 - 无法打印出int常量的名字,导致在日志中看到的是int常量的数字而不是友好可读的字符串。 - 有人将int常量用String常量代替来解决上条的打印问题,然而,基于字符串的枚举常量在比较的时候性能糟糕,而且很容易被人误用字面量代替,导致产生大量硬编码。何况字符串的常量也不能解决前两个问题。
优点如下: - 类型安全 - 有自己的命名空间 - 实例受控,每个枚举类型的枚举元素都是全局唯一的,且为final的,客户端既不能新建也不能修改或者继承它们(基于这个特性,在比较两个枚举元素的时候,你可以直接使用==
运算符,因为每个枚举元素的对象都是全局唯一的,如果两个枚举元素相等,那么它们的对象肯定是同一个对象。反之亦然) - 允许添加任意的方法和域 - 枚举类型也可以实现接口,可以有抽象方法 - 枚举类型默认重写了toString方法,使你可以直接打印出枚举的名称
给一个枚举的例子出来:
public enum Planet {
MERCURY(3.302e+23, 2.439e6), VENUS(4.869e+24, 6.052e6), EARTH(5.975e+24,
6.378e6), MARS(6.419e+23, 3.393e6), JUPITER(1.899e+27, 7.149e7), SATURN(
5.685e+26, 6.027e7), URANUS(8.683e+25, 2.556e7), NEPTUNE(1.024e+26,
2.477e7);
private final double mass; // In kilograms
private final double radius; // In meters
private final double surfaceGravity; // In m / s^2
// Universal gravitational constant in m^3 / kg s^2
private static final double G = 6.67300E-11;
// Constructor
Planet(double mass, double radius) {
this.mass = mass;
this.radius = radius;
surfaceGravity = G * mass / (radius * radius);
}
public double mass() {
return mass;
}
public double radius() {
return radius;
}
public double surfaceGravity() {
return surfaceGravity;
}
public double surfaceWeight(double mass) {
return mass * surfaceGravity; // F = ma
}
}
装载和初始化枚举时,有空间和时间的成本。但是,如书中所说,除了受资源约束的设备,如手机和烤面包机,在实践中不必在意这个问题……
本条讲枚举类型默认带一个方法:ordinal()
,这个方法返回枚举常量在枚举中定义的时候的序号(当然是从0开始的)。 然后很多人非常愉快地使用这个方法来返回常量的序号,并用这个序号做逻辑。 书中指出:不建议这么做。 因为枚举常量的位置会变,这是无法保证的。而且想要再添加一个与已经用过的序号有所关联的枚举常量,就难了。 应该使用实例域来代替这种不靠谱的方法:
public enum Ensemble {
SOLO(1), DUET(2), TRIO(3), QUARTET(4), QUINTET(5), SEXTET(6), SEPTET(7), OCTET(
8), DOUBLE_QUARTET(8), NONET(9), DECTET(10), TRIPLE_QUARTET(12);
private final int numberOfMusicians;
Ensemble(int size) {
this.numberOfMusicians = size;
}
public int numberOfMusicians() {
return numberOfMusicians;
}
}
本条主要讲的是JDK提供了一个叫做EnumSet
的类,可以为我们提供多个枚举常量的集合,并且轻松实现交集并集等操作。 它的底层在枚举元素数小于64个时,使用的是long类型实现的位域来进行操作的,因此在小于64个元素的时候,它和传统的利用位域实现的集合性能相当。
本条主要讲的是jdk提供了一个叫做EnumMap
的类,如果我们要用枚举作为键来归类某些东西,最好使用Enummap
这个类而不是用ordinal
方法去得到枚举常量的序数来作为键。