您的位置:首页 > Web前端

枚举类型浅析

2017-01-09 00:00 176 查看
回头再写备注

1、枚举类就是class并且是一个不可被继承的final class,其枚举值都是public static final的。

2、既然枚举类是class其就会有构造、方法、数据域。但是枚举类的构造器有很大不同:首先,构造器只是在构造枚举值时使用;其次,构造器是private的,不允许为public(这样可以保证外部代码无法新构造枚举类的实例。这也是完全符合情理的,因为我们知道枚举值是public static final的常量而已。 但枚举类的方法和数据域可以允许外部访问)。

3、所有枚举类都继承了Enum的方法,下面我们详细介绍这些方法。
(1) ordinal()方法: 返回枚举值在枚举类种的顺序。这个顺序根据枚举值声明的顺序而定。
(2) compareTo()方法: Enum实现了java.lang.Comparable接口,因此可以比较象与指定对象的顺序。Enum中的compareTo返回的是两个枚举值的顺序之差。当然,前提是两个枚举值必须属于同一个枚举类,否则会抛出ClassCastException()异常。
(3) values()方法: 静态方法,返回一个包含全部枚举值的数组。
(4) toString()方法: 返回枚举常量的名称。
(5) valueOf()方法: 这个方法和toString方法是相对应的,返回带指定名称的指定枚举类型的枚举常量。
(6) equals()方法: 比较两个枚举类对象的引用。

4、枚举类可以在switch语句中使用。

5.特定于常量的枚举方法

6.策略枚举(strategy enum)

package cn.com.imooc;

//Enum type with data and behavior
public enum Planet {

MERCURY(3.302e+23,2.439e6),
VENUS(4.869E+24,6.052e6),
EARCH(5.975e+24,6.378e6),
MARS (6.419e+23,3.393e6),
JUPITER(1.899e+27,7.149e7),
STATURN(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
}
}

测试:

package cn.com.test;

import cn.com.imooc.Planet;

public class WeightTable {

public static void main(String[] args) {

double earthWeight = Double.parseDouble("175");
double mass = earthWeight/Planet.EARCH.surfaceGravity();
for(Planet p : Planet.values()){
System.out.printf("Weight on %s is %f%n",p,p.surfaceWeight(mass));
}
}
}

枚举类实现最基本的加减乘除:

package cn.com.imooc;

//Enum type that switches on its own value -questionable
/**
* 枚举类实现最基本的加减乘除
* @author xiaomingtongxie
*
*/
public enum Operation {
PLUS,MINUS,TIMES,DIVIDE;

//Do the arithmetic op represented by this constant
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("Unkonwn op:" + this);
}

}

枚举类型是编译安全类型,加入增加了新的运算枚举类,而没有在switch 中添加对应的条件,编译时不会报错,但运行时会出错。

于是有了,特定于常量的方法实现,优化代码如下:

package cn.com.imooc;

//Enum type with constant-specific method implementations
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;
}
};

abstract double apply(double x, double y);
}

枚举类中的抽象方法必须被它所有常量中的具体方法所覆盖,这样就不存在有编译时错误了。

package cn.com.imooc;

//Enum type with constant-specific method implementations
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 static void main(String[] args) {
//Operation obj = Operation.MINUS;
double x = Double.parseDouble("2");
double y = Double.parseDouble("4");
for (Operation obj : Operation.values()) {
System.out.printf("%f %s %f = %f%n",x,obj,y,obj.apply(x, y));
}
}

在枚举类中覆盖toString,要考虑编写一个fromString方法,见定制的字符串表示法变回相应的枚举。

//Implementing a fromString method on an enum type
private static final Map<String,Operation> stringToEnum = new HashMap<String, Operation>();
static{ // Initialize map from constant name to enum constant
for (Operation obj : values()) {
stringToEnum.put(obj.toString(), obj);
}
}

//Return Operation for string, or null if string is invalid
public static Operation fromString(String symbol)
{
return stringToEnum.get(symbol);
}

试图使每个常量都从自己的构造器将自身放入到map中,会导致编译时错误。枚举构造器不可以访问枚举的静态域,除了编译时常量域除外。

//实现工作日正常工资,双休加班工资是平时一半

package cn.com.imooc;

//Enum tha switches on its value to share code-questionable
public enum PayrollDay {

MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
private static final int HOURS_PER_SHIFT = 8;

double pay(double hourWorked, double payRate) {
double basePay = hourWorked * payRate;

double overtimePay; // Calculate overtime pay
switch (this) {
case SATURDAY:
case SUNDAY:
overtimePay = hourWorked * payRate / 2;
default: // Weekdays
overtimePay = hourWorked <= HOURS_PER_SHIFT ? 0 : (hourWorked
* payRate / 2);
break;
}
return basePay + overtimePay;
}
}

但是,如果添加了个特殊的枚举,代表假期天数的特殊值,但忘记添加相应的case.程序依然可以编译,但pay方法会悄悄地将假期的工资算成域常量工作日的相同。

每当添加一个枚举常量时,就强制选择一种加班报酬策略。

下面就是策略枚举的实现:

package cn.com.imooc;

//The strategy enum pattern
public 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);
}
// The strategy enum type
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);
}
}
}

这种思想就是将加班工资计算一道一个私有的嵌套枚举中,将这个策略枚举的实例转到PayrollDay枚举的构造器中。

当然,switch 还是有用的,比如说加减法倒置,乘除法倒置

//Switch on an enum to simulate a missing method
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("Unkown op:" + op);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息