java 枚举类型使用总结
注:阅读了effective java 讲诉enum的部分,做下笔记,下文中大部分代码来自effective java书中
枚举类型是指由一组固定的常量组成的合法值得类型。
使用枚举的好处:a,因为没有可以访问的构造器,枚举类型是真正的final;
b,枚举类型提供类编译时的类型安全。如:函数中声明一个参数类型为枚举类型的Apple时,那么调用方法时传递到参数上的任何非null对象一定是Apple的值之一, 而是用静态常量就无法保证;
c,包含同名常量的多个枚举类型可以和平共处,每个类型都有自己的命名空间
d,枚举类型允许添加任意的方法和域,并可实现接口。
1,常见的一组简单的枚举
如:
public enum Apple { FUJI,PIPPIN,CRANNY_SMITH }
2,带有具体值的枚举(可自定义方法)
public enum Apple { FUJI(1), PIPPIN(2), CRANNY_SMITH(3); private final int code; Apple(int code) { this.code = code; } public int getCode() { return code; } public static Apple fromCode(int code) { for (Apple apple : Apple.values()) { if (apple.getCode() == code) return apple; } return null; } }
3,多个参数,并带有运算方法
public enum Planet { MERCURY(3.303e+23, 2.4397e6), VENUS(4.869e+24, 6.0518e6), EARTH(5.976e+24, 6.37814e6), MARS(6.421e+23, 3.3972e6), JUPITER(1.9e+27, 7.1492e7), SATURN(5.688e+26, 6.0268e7), URANUS(8.686e+25, 2.5559e7), NEPTUNE(1.024e+26, 2.4746e7), PLUTO(1.27e+22, 1.137e6); private final double mass; private final double radius; private final double surfaceGravity;// m/ s^2 public 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 surfaceWeight(double otherMass) { return otherMass * surfaceGravity; } }
4,根据不同的常量有不同的方法
switch方法 ----不推荐(有可能新添加了常量却没有在switch中加入就悲剧了)
public enum Operation { PLUS("+"), MINUS("-"), TIMES("*"), DIVIDE("/"); private final String symbol; Operation(String symbol){ this.symbol=symbol; } public String getSymbol() { return symbol; } 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 operation: "+this); }
推荐:constant-specific method implementation
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; } }; private final String symbol; Operation(String symbol) { this.symbol = symbol; } public String getSymbol() { return symbol; } public abstract double apply(double x, double y); }
5,策略枚举 strategy enum
先来看一种情况:通过一周的工作时间来计算工资,工作时间8小时,额外算加班,周末工作也算加班
首先我们可以使用switch来做,这样看起来十分简单
public enum PayrollDay { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FIRDAY, SATURDAY, SUNDAY; private static final int HOURS_PER_SHIFT = 8; double pay(double hoursWorked, double payRate) { double basePay = hoursWorked * payRate; double overtimePay; switch (this) { case SATURDAY: case SUNDAY: overtimePay = hoursWorked * payRate * 2; default: overtimePay = hoursWorked <= HOURS_PER_SHIFT ? 0 : (hoursWorked - HOURS_PER_SHIFT) * payRate * 2; break; } return basePay + overtimePay; } }
但是同样有可能出现上面提到不严谨的问题,当枚举常量增加时,switch可能忘记加入
使用策略枚举时 如下:
public enum PayrollDay { MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY( PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FIRDAY(PayType.WEEKDAY), SATURDAY( PayType.WEEKEND), SUNDAY(PayType.WEEKEND); private final PayType payType; PayrollDay(PayType payType) { this.payType = payType; } public PayType getPayType() { return payType; } double pay(double hoursWorked, double payRate) { return payType.pay(hoursWorked, payRate); } enum PayType { WEEKDAY { @Override double overtimePay(double hours, double payRate) { return hours < HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT) * payRate * 2; } }, WEEKEND { @Override double overtimePay(double hours, double payRate) { return hours * payRate * 2; } }; private static final int HOURS_PER_SHIFT = 8; abstract double overtimePay(double hours, double payRate); double pay(double hoursWorked, double payRate) { double basePay = hoursWorked * payRate; return basePay + overtimePay(hoursWorked, payRate); } } }
6,上面几个例子中都不推荐时间switch,那么什么时候使用呢
枚举中的switch语句适用于给外部的枚举类型增加特定于常量的行为。如:上面例子中的operation 如果希望他有一个方法返回对应的逆运算
public static Operation inverse(Operation op) { switch (op) { case PLUS: return Operation.MINUS; case MINUS: return Operation.PLUS; case TIMES: return Operation.DIVIDE; case DIVIDE: return Operation.TIMES; default: throw new AssertionError("unknown operation : " + op); } }