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;
//例如apple和orange都有HAN这个品种,那么必须加前缀,即APPLE_HAN和ORANGE_HAN这两个变量来区分
//因为int枚举为编译时常量
public static final String APPLE_FUJI = "FUJI";
public static void main(String[] args) {
//没使用常量的属性名APPLE_FUJI,而是将字符串常量硬编码到客户端代码
//如果写错了,编译时不报错,运行时可能会有问题
System.out.println("FUJI1");
}
//因为不像int枚举模式一样,将常量值编译到了客户端代码中
//7. 如果一个枚举类具有普遍适用性,可以将它设计为一个顶层类,例如java.math.RoundingMode,表示十进制小数的舍入模式(四舍五入还是什么),它被用于BigDecimal类,但该API的设计者,还希望程序员你重用这个枚举类,增强自己设计的API与他们设计的API的一致性,因此设计为顶层类
//8. 如果枚举类只被用在特定的顶层类中,那就应该把该枚举类设计为这个顶层类的一个成员类(内部的枚举类)
public enum Planet {
//5. 但删除一个枚举值时,客户端用到这个枚举值的地方重新编译时会失败,如果不重新编译,执行时也会报错,不会像int枚举模式那样,不报错,但给出错误的结果
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);
//1. 设计枚举类的初衷,就是希望它是不可变的类,为了实现这一点,应该将成员变量都设置为final
//2. 最好private修饰,并提供getter方法
private final double mass;
private final double radius;
private final double surfaceGravity;
private static final double G = 6.67300E-11;
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;
}
//6. 如果方法只用在枚举类,或其所在的包中,最好用private或default修饰,除非客户端需要调用该方法,可以使用public、protected
private void wusihan() {
}
public static void main(String[] args) {
//3. 打印一个在地球上1234g的物体,在各个星球上的重量
double earthWeight = Double.parseDouble("1234");
double mass = earthWeight / Planet.EARTH.surfaceGravity();
for (Planet p : Planet.values())
//4. 打印枚举类对象p时,默认调用其toString方法,而枚举类的toString方法默认返回其枚举值的字符串,也可以覆盖toString方法, 进行修改
System.out.printf("Weight on %s is %f%n", p, p.surfaceWeight(mass));
}
}
public enum Operation {
PLUS, MINUS, TIMES, DIVIDE;
public double apply(double x, double y) {
switch (this) {
case PLUS:
return x + y;
case MINUS:
return x - y;
case TIMES:
return x * y;
case DIVIDE:
return x / y;
}
throw new AssertionError("Unknown op: " + this);
}
}
public enum Operation {
//1. 该括号后的内容,书中叫做特定于常量的类主体(constant-specific class body),其实constant-specific翻译应该是独特的常量,强调每个常量中的方法实现不同
PLUS {
public double apply(double x, double y) {
return x + y;
}
},
MINUS {
public double apply(double x, double y) {
return x - y;
}
},
TIMES {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE {
public double apply(double x, double y) {
return x / y;
}
};
public abstract double apply(double x, double y);
}
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public enum Operation {
PLUS("+") {
public double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
public double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
public double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
public double apply(double x, double y) {
return x / y;
}
};
// 1. 当枚举值不同时,其属性symbol的值也不同,因此叫做特定于常量的数据
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return symbol;
}
public abstract double apply(double x, double y);
//3. Stream 就如同一个高级版本的 迭代器(Iterator),单向,不可往复,数据只能遍历一次,遍历过一次后即用尽了,就好比流水从面前流过,一去不复返
//4. 以Operation的toString作为key,Operation对象作为value的map
private static final Map<String, Operation> stringToEnum = Stream.of(values())
.collect(Collectors.toMap(Object::toString, e -> e));
//2. fromString方法,可以通过传入枚举值的toString打印的结果,得到该枚举值
public static Optional<Operation> fromString(String symbol) {
return Optional.ofNullable(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));
}
}
//我觉得这个操作是可以的,怀疑作者的本意是想表达,static的这种map,枚举值做不到通过构造器将自身放入,因为枚举构造器压根无法访问枚举的静态域
//新成员,定义一个映射
public Map map = new HashMap();
//构造器
Operation(String symbol) {
this.symbol = symbol;
//将自身放入映射,编译不会报错
map.put("/",this);
}
private static final String name = "handidiao";
private static final String name1 = new String("handidiao");
Operation(String symbol) {
this.symbol = symbol;
//这是因为在枚举类中,枚举值必须写在最前面,而枚举值默认由public static final修饰,属于静态域,而静态域的初始化,是按顺序的,也就是说,构造器被调用时,实际上你想使用的其他静态域还没被初始化,因此不允许使用
//而如果该静态域为编译时常量,由于编译后,该值被直接替换为一个常量,因此可以使用
System.out.println(name);
//System.out.println(name1);
//1. 这导致构造器无法将自身放入 静态的映射中
//stringToEnum.put("123", DIVIDE);
//2. 这导致构造器中无法访问其他枚举值
//System.out.println(TIMES);
}
实际上这个方案的本质,是为枚举值,传入一个实例(该实例可以是另一个枚举类的枚举值),然后枚举值的方法中,转为调用该实例的方法,可以减少样板代码
enum PayrollDay {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
private static final int MINS_PER_SHIFT = 8 * 60;
int pay(int minutesWorked, int payRate) {
int basePay = minutesWorked * payRate;
int overtimePay;
switch (this) {
case SATURDAY:
case SUNDAY:
overtimePay = basePay / 2;
break;
default:
overtimePay = minutesWorked <= MINS_PER_SHIFT ? 0 : (minutesWorked - MINS_PER_SHIFT) * payRate / 2<