# Enum 枚举

## Enumeration

enum type是由一组固定的常量组成的类型，比如四个季节、扑克花色。

``````public static final int APPLE_FUJI = 0;
public static final int APPLE_PIPPIN = 1;
public static final int APPLE_GRANNY_SMITH = 2;

public static final int ORANGE_NAVEL = 0;
public static final int ORANGE_TEMPLE = 1;
public static final int ORANGE_BLOOD = 2;
``````

``````int i = (APPLE_FUJI - ORANGE_TEMPLE) / APPLE_PIPPIN;
``````

（ps:我觉得更遭的是有人直接把常量值写到代码里...）

``````public enum Apple  { FUJI, PIPPIN, GRANNY_SMITH }
public enum Orange { NAVEL, TEMPLE, BLOOD }
``````

enum本身就是final，所以很多时候也直接用enum实现singleton。
enum在编译时是类型安全的，比如有地方声明了上面代码中的Apple类型的参数，那么被传到该参数的引用肯定是三种苹果之一。

``````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
this.mass = mass;
}

public double mass() {
return mass;
}

}

public double surfaceGravity() {
return surfaceGravity;
}

public double surfaceWeight(double mass) {
return mass * surfaceGravity; // F = ma
}
}
``````

``````public class WeightTable {
public static void main(String[] args) {
double earthWeight = Double.parseDouble(args[0]);
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for (Planet p :  Planet.values())
System.out.printf("Weight on %s is %f%n",p, p.surfaceWeight(mass));
}
}
``````

``````import java.util.HashMap;
import java.util.Map;

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);

private static final Map<String, Operation> stringToEnum = new HashMap<String, Operation>();
static {
for (Operation op : values())
stringToEnum.put(op.toString(), op);
}

public static Operation fromString(String symbol) {
return stringToEnum.get(symbol);
}

public static void main(String[] args) {
double x = Double.parseDouble(args[0]);
double y = Double.parseDouble(args[1]);
for (Operation op : Operation.values())
System.out.printf("%f %s %f = %f%n", x, op, y, op.apply(x, y));
}
}
``````

``````enum PayrollDay {
MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

private final PayType payType;

PayrollDay(PayType payType) {
this.payType = payType;
}

double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
}

private enum PayType {
WEEKDAY {
double overtimePay(double hours, double payRate) {
return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
* payRate / 2;
}
},
WEEKEND {
double overtimePay(double hours, double payRate) {
return hours * payRate / 2;
}
};
private static final int HOURS_PER_SHIFT = 8;

abstract double overtimePay(double hrs, double payRate);

double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}
``````

## Annotation

• 错误的文字拼写并不会有任何提示，直到运行时才会发现出了问题。
• 其次，这种方式无法特指某个程序元素，比如用户将某个类名的开头做了特殊命名，希望作用于类中所有的方法，结果可能没有提示、没有效果、没有意义。
• 而且，这种方式太单调，比如我想和某个方法的参数或者和声明抛出的异常进行交互。当然，反射也可以，但问题是我如何在不知道用户行为的情况下提供反射方法。

``````import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Test {
//..
}
``````

``````import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ExceptionTest {
Class<? extends Exception>[] value();
}
``````

``````import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class RunTests {
public static void main(String[] args) throws Exception {
int tests = 0;
int passed = 0;
Class testClass = Class.forName(args[0]);
for (Method m : testClass.getDeclaredMethods()) {
if (m.isAnnotationPresent(Test.class)) {
tests++;
try {
m.invoke(null);
passed++;
} catch (InvocationTargetException wrappedExc) {
Throwable exc = wrappedExc.getCause();
System.out.println(m + " failed: " + exc);
} catch (Exception exc) {
System.out.println("INVALID @Test: " + m);
}
}

if (m.isAnnotationPresent(ExceptionTest.class)) {
tests++;
try {
m.invoke(null);
System.out.printf("Test %s failed: no exception%n", m);
} catch (Throwable wrappedExc) {
Throwable exc = wrappedExc.getCause();
Class<? extends Exception>[] excTypes = m.getAnnotation(
ExceptionTest.class).value();
int oldPassed = passed;
for (Class<? extends Exception> excType : excTypes) {
if (excType.isInstance(exc)) {
passed++;
break;
}
}
if (passed == oldPassed)
System.out.printf("Test %s failed: %s %n", m, exc);
}
}
}
System.out.printf("Passed: %d, Failed: %d%n", passed, tests - passed);
}
}
``````

Inexplicably, the authors of the ObjectOutputStream API did not take advantage of the Serializable interface in declaring the write method.

The Set interface places additional stipulations, beyond those inherited from the Collection interface, on the contracts of all constructors and on the contracts of the addequals and hashCode methods. Declarations for other inherited methods are also included here for convenience. (The specifications accompanying these declarations have been tailored to the Set interface, but they do not contain any additional stipulations.)

Set并没有改进Collection的契约，只是为实现类多提供了一种抽象描述。