Java 枚举
Enum
参考《Effective Java》
Java1.5之后
- 枚举提够了编译时的类型安全
- 包含同名常量的多个枚举类型可以在一个系统中和平共处,因为每个类型都有自己的命名空间。
- 枚举类型允许添加任意的方法和域,并且实现任意的接口。
Sample:
每个枚举常量后面括号中的数值,就是传递给构造器的参数。
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;
private final double radius;
private final double surfaceGravity;
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
}
}
下面是一个简短的程序,根据某个物体在地球上的重量,打印出一张很棒的表格,显示出该物体在所有8颗行星上的重量。
Planet就像所有的枚举一样,它有一个静态的values方法,按照声明顺序返回它的值数组。
toString方法返回每一个枚举值的声明名称。
public class WeightTable {
/**
* @param args
*/
public static void main(String[] args) {
double earthWeight = Double.parseDouble("175");
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for(Planet p : Planet.values()) {
System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
}
}
}
输出结果为:
Weight on MERCURY is 66.133672
Weight on VENUS is 158.383926
Weight on EARTH is 175.000000
Weight on MARS is 66.430699
Weight on JUPITER is 442.693902
Weight on SATURN is 186.464970
Weight on URANUS is 158.349709
Weight on NEPTUNE is 198.846116
与枚举常量相关的有些行为,可能只需要用在定义了枚举的类或者包中。这种行为最好被实现成私有的(private)或者包级私有(default)的方法。于是,每个枚举常量都带有一组隐蔽的行为,这使得包含枚举的类或者包在遇到这种常量时都可以做出适当的反应。就像其他的类一样,除非迫不得已要将枚举方法导出至它的客户端,否则都应该将它声明为私有的,如有必要,则声明为包级私有的。
如果一个枚举具有普遍适用性,它就应该称为一个顶层类(top-level class);如果它只是被用在一个特定的顶层类中,它就应该成为该顶层类的一个成员类。
可以在枚举类型中声明一个抽象的apply方法,并在特定于常量的类主体中,用具体的方法覆盖每个常量的抽象apply方法。这种方法被称作特定于常量的方法实现。
public enum Operation {
PLUS("+") { double apply(double x, double y) { return x + y; } },
MINUS("-") {double apply(double x, double y) { return x - y; }},
TIMES("*") {double apply(double x, double y) { return x * y; }},
DIVIDE("/") {double apply(double x, double y) { return x / y; }};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
abstract double apply(double x, double y);
}
永远不要根据枚举的序数导出与它关联的值,而是要将它保存在一个实例域中:
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;
}
}
枚举自己处理序列化
使用一个包含单个元素的枚举类型,可以用作单例模式:
public enum SingletonElvis {
INTENCE(123);
private SingletonElvis(int intValue) {
this.intValue = intValue;
}
private final int intValue;
public void testMethod() {
System.out.println("intValue: " + intValue);
}
}
public class SingletonEnumTest {
public static void main(String[] args) {
SingletonElvis.INTENCE.testMethod();
}
}
枚举单例,JVM对序列化有保证
创建枚举默认就是线程安全