JDK1.5之前的枚举
在JDK1.5之前是没有enum这个关键字的,那么那个时代是怎么实现枚举的呢?主要是通过私有化构造器,然后在类里面创建静态final的对象,在类的外面通过 ** 类名.对象名 ** 来使用枚举的,如下:
class Season{
String name;
String description;
private Season(String name, String description) {
this.name = name;
this.description = description;
}
public static final Season SPRING = new Season("Spring", "春天");
public static final Season SUMMER = new Season("Summer", "夏天");
public static final Season AUTUMN = new Season("Autumn", "秋天");
public static final Season WINTER = new Season("Winter", "冬天");
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
}
// 测试方法
@Test
public void test1(){
Season Spring = Season.SPRING;
Season Summer = Season.SUMMER;
Season Autumn = Season.AUTUMN;
Season Winter = Season.WINTER;
System.out.println(Spring);
System.out.println(Spring.getName()+" "+Spring.getDescription());
/**
* 打印结果:
* Season{name='Spring', description='春天'}
* Spring 春天
*/
}
JDK1.5之后的枚举
在JDK1.5之后,出现了enum关键字,它的作用就是简化前面使用枚举的繁琐,解放程序员的双手的:
enum Season1{
SPRING("Spring","春天"),
SUMMER("Summer", "夏天"),
AUTUMN("Autumn", "秋天"),
WINTER("Winter", "冬天");
String name;
String description;
Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
}
@Test
public void test2(){
Season1 Spring = Season1.SPRING;
Season1 Summer = Season1.SUMMER;
System.out.println(Spring);
Season1[] season1s = Season1.values();
for(Season1 season1: season1s){
System.out.println(season1 + " ----------"+season1.getName()+"--"+season1.getDescription());
}
/**
* 打印结果:
* Season{name='Spring', description='春天'}
* Season{name='Spring', description='春天'} ----------Spring--春天
* Season{name='Summer', description='夏天'} ----------Summer--夏天
* Season{name='Autumn', description='秋天'} ----------Autumn--秋天
* Season{name='Winter', description='冬天'} ----------Winter--冬天
*/
}
使用enum之后只是有几个点要注意一下的:
- 对象名紧跟在类名后面
- 对象名后面的参数其实就是传向构造器中的参数
在我看来,其实enum就是一个类,只是这个类定义的时候与其他类不同而已,它的使用方法也略微有点不同,它有一些自己特有的方法,比如values(),valueOf(String str)等。同样,作为一个类,它也能实现接口,比如:
interface EnumInterface{
void show();
}
enum Season1 implements EnumInterface{
SPRING("Spring","春天"){
@Override
public void show(){
System.out.println("Spring show()");
}
},
SUMMER("Summer", "夏天"){
@Override
public void show(){
System.out.println("Summer show()");
}
},
AUTUMN("Autumn", "秋天"){
@Override
public void show(){
System.out.println("Autumn show()");
}
},
WINTER("Winter", "冬天"){
@Override
public void show(){
System.out.println("Winter show()");
}
};
String name;
String description;
Season1(String name, String description) {
this.name = name;
this.description = description;
}
public String getName() {
return name;
}
public String getDescription() {
return description;
}
@Override
public String toString() {
return "Season{" +
"name='" + name + '\'' +
", description='" + description + '\'' +
'}';
}
}
@Test
public void test2(){
Season1 Spring = Season1.SPRING;
Season1 Summer = Season1.SUMMER;
System.out.println(Spring);
Season1[] season1s = Season1.values();
for(Season1 season1: season1s){
System.out.println(season1 + " ----------"+season1.getName()+"--"+season1.getDescription());
season1.show();
}
/**
* 打印结果:
* Season{name='Spring', description='春天'}
* Season{name='Spring', description='春天'} ----------Spring--春天
* Spring show()
* Season{name='Summer', description='夏天'} ----------Summer--夏天
* Summer show()
* Season{name='Autumn', description='秋天'} ----------Autumn--秋天
* Autumn show()
* Season{name='Winter', description='冬天'} ----------Winter--冬天
* Winter show()
*/
}
此时,在每个对象中重写show()方法,可以使得每个对象都具有不同的行为(实现策略模式),倘若只是在类中重写show()方法,则所有的对象都只是具有一个相同的行为而已。
小结
枚举并非什么神奇的东西,它只不过是帮助我们简化了一些操作而已,比如我们之前写一些枚举状态之类的东西,可能是这样:
class Status{
public static final String NEW = "NEW";
public static final String FINISHED = "FINISHED";
}
用了枚举之后就是这样的,在枚举类的外部还可以使用values()来获取一组Status的对象的数组,极大的方便了我们对状态的遍历。
enum Status1{
NEW("NEW"),
FINISHED("FINISHED");
private String str;
private Status1(String str){
this.str = str;
}
}
Enum源码分析
假设有这么一个简单的枚举:
public enum EnumTest {
SOMEONE,
ANOTHER_ONE
}
首先对其进行编译,然后使用命令javap -verbose EnumTest.class
对其反编译,得到如下部分:
public final class com.lin.EnumTest extends java.lang.Enum<com.lin.EnumTest>
所以,对于Java来说,枚举是一个语法糖。
使用策略枚举代替策略模式
普通写法:
enum Operation {
PLUS,MINUS,TIMES,DIVIDE;
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("Unknow op: " + this);
}
}
使用策略枚举使得代码更加健壮、扩展性更好:
enum Operation {
PLUS("+") {
@Override
double apply(double x, double y) {
return x + y;
}
},
MINUS("-") {
@Override
double apply(double x, double y) {
return x - y;
}
},
TIMES("*") {
@Override
double apply(double x, double y) {
return x * y;
}
},
DIVIDE("/") {
@Override
double apply(double x, double y) {
return x / y;
}
};
private final String symbol;
Operation(String symbol) {
this.symbol = symbol;
}
@Override
public String toString() {
return this.symbol;
}
abstract double apply(double x, double y);
}
优雅的嵌套枚举策略模式:
enum PayrollDay {
MonDAY(PayType.WEEKDAY),
WEEKDAY(PayType.WEEKDAY),
TUESDAY(PayType.WEEKDAY),
WENDESDAY(PayType.WEEKDAY),
THURSDAY(PayType.WEEKDAY),
FRIDAY(PayType.WEEKDAY),
SATURDAY(PayType.WEEKEND),
SUNDAY(PayType.WEEKEND);
private PayType payType;
PayrollDay(PayType payType) {
this.payType = payType;
}
double pay(double hoursWorked, double payRate) {
return payType.pay(hoursWorked, payRate);
}
//这里是嵌套枚举
private enum PayType {
WEEKDAY {
@Override
double overtimePay(double hrs, double payRate) {
return 0;
}
}, WEEKEND {
@Override
double overtimePay(double hrs, double payRate) {
return 0;
}
};
private static final int HOURS_PRE_SHIFT = 8;
abstract double overtimePay(double hrs, double payRate);
double pay(double hoursWorked, double payRate) {
double basePay = hoursWorked * payRate;
return basePay + overtimePay(hoursWorked, payRate);
}
}
}