一、引言
在进行系统开发时,我们常会用数字或者字母去存储一些枚举项。比如用M表示男、F表示女,或者用1表示经理、2表示前台、3表示收银台、4表示厨房等等。但是如果在代码中出现:
if(type == "1"){
......
}else if(type == "2"){
...
}....
类似上述的代码,对于新员工或者系统维护人员来说,是一件非常头疼的事情。代码可读性非常低,而且很容易出错。
在JAVA SE5以下,JAVA语言并没有提供枚举类型,当时sun公司进行设计时,许多地方借鉴了C/C++语言,但是也取消了C/C++中部分数据类型,譬如枚举类型、结构体等。sun公司认为用普通类就可以完成枚举类型的功能。但是随着信息系统的日益壮大,sun公司又重新开始考虑枚举类型的必要性了。那么,我们先来利用普通类去实现枚举类型,体验一下枚举类型为我们带来的好处。
二、普通类实现枚举类型
假设我们要用MON、SUN表示周一和周日(周二~周六做法雷同),我们希望用Week.MON和Week.SUN进行调用。代码如下:
public class MyWeekEnum {
private MyWeekEnum() { //防止new对象,即用户只能得到指定的类型
}
//实现用户只能得到MON和SUN
public static MyWeekEnum MON = new MyWeekEnum();
public static MyWeekEnum SUN = new MyWeekEnum();
}
public static void main(String[] args) {
MyWeekEnum week = MyWeekEnum.MON;
if (week == MyWeekEnum.SUN) {
System.out.println("sun");
} else if (week == MyWeekEnum.MON) {
System.out.println("mon");
} //输出为:mon
}
这样,一个最简单的枚举就写完了。接下来,我们考虑枚举类型是不是可以和其他普通类一样,有自己的方法。比如说我想知道明天是周几,即我想添加一个getNextDay()这样一个方法。我们可以这样实现:
public class MyWeekEnum {
private MyWeekEnum() { // 防止new对象,即用户只能得到指定的类型
}
// 实现用户只能得到MON和SUN
public static MyWeekEnum MON = new MyWeekEnum();
public static MyWeekEnum SUN = new MyWeekEnum();
public MyWeekEnum getNextDay() {
if (this == MON) {
return SUN;
} else {
return MON;
}
}
}
public static void main(String[] args) {
MyWeekEnum week = MyWeekEnum.MON;
System.out.println(week.getNextDay() == MyWeekEnum.MON); //falise
System.out.println(week.getNextDay() == MyWeekEnum.SUN); //true
}
到目前为止,我们确实实现了枚举类型以及为枚举类型添加方法。但是由于枚举类型大家的地位是一样的,大家可能都希望能够自己去实现具体的方法,只希望
MyWeekEnum能够提供一个"接口"告诉我需要实现哪些方法。而且如果用上述的方法去实现,一旦枚举类型的量大了,需要书写一大堆if...else,容易出错。于是我们进行了如下重构:
public abstract class MyWeekEnum {
private MyWeekEnum() { // 防止new对象,即用户只能得到指定的类型
}
// 实现用户只能得到MON和SUN
public static MyWeekEnum MON = new MyWeekEnum() {
@Override
public MyWeekEnum getNextDay() { //具体实现
return SUN;
}
};
public static MyWeekEnum SUN = new MyWeekEnum() {
@Override
public MyWeekEnum getNextDay() { //具体实现
return MON;
}
};
public abstract MyWeekEnum getNextDay(); //抽象方法
}
这里需要注意的是MyWeekEnum需要定义成抽象类。MON和SUN变成了MyWeekEnum的子类,并重写父类方法,有点小多态的味道。最后,我们尝试一下在枚举类型里面添加常量。代码如下:
public abstract class MyWeekEnum {
private MyWeekEnum() { // 防止new对象,即用户只能得到指定的类型
}
private MyWeekEnum(String describe) {
this.describe = describe;
}
// 实现用户只能得到MON和SUN
public static MyWeekEnum MON = new MyWeekEnum("周一") {
@Override
public MyWeekEnum getNextDay() {
return SUN;
}
};
public static MyWeekEnum SUN = new MyWeekEnum("周日") {
@Override
public MyWeekEnum getNextDay() {
return MON;
}
};
public abstract MyWeekEnum getNextDay();
private String describe;
public String getDescribe() {
return this.describe;
}
}
public static void main(String[] args) {
MyWeekEnum week = MyWeekEnum.MON;
System.out.println(week.getDescribe()); //周一
}
三、枚举类型使用
在第二小节中,我们实现了JAVA枚举类型大部分常见的功能。相信如果了解了第二小节的内容再看JAVA的枚举类型会轻松不少。首先,我们来看看JAVA的枚举类型是如何定义的:
public enum Week {
MON,SUN;
}
这样一个枚举就定义好了,调用方式:Week.SUN、Week.MON,是不是觉得非常方便呢?其实,我们在创建enum时,编译器会为你生成一个相关的类,这个类继承自java.lang.Enum(所以enum类型不能再继承其他类了,但是可以实现其他多个接口),它自带了一些方法,接下来我们去研究一下这些方法。
1、values() 它可以返回enum实例的数组,而且他们的下标就是我们声明的顺序。
2、name() 它返回enum实例声明时的名称。
for (Week w : Week.values()) {
System.out.println(w.name());
}//输出为:MON SUN
3、ordinal() 它返回一个int,是每一个enum实例在声明时的次序,从0开始编号。
4、getDeclaringClass() 它可以返回enum实例所属的enum类。
5、valueOf() 它会根据给定的名称返回相应的enum实例,多用于web开发中,我们接收web前端提交的字符串,去生成一个enum实例。
Week week = Week.valueOf("MON"); // 模拟从web前端取到MON字符串
System.out.println(week.name() + " " + week.getDeclaringClass()); //MON class edu.fjnu.test.Week
接下来我们来看看在enum中添加方法。其实和我们上述的实现大同小异。
public enum Week {
MON(){
@Override
public Week getNextDay() {
return SUN;
}
},
SUN(){
@Override
public Week getNextDay() {
return MON;
}
};
public abstract Week getNextDay();
}
最后我们来看看枚举类型如何实现带参构造函数:
public enum Week {
MON("周一") {
@Override
public Week getNextDay() {
return SUN;
}
},
SUN("周日") {
@Override
public Week getNextDay() {
return MON;
}
};
private Week() {
}
private Week(String describe) {
this.describe = describe;
}
public abstract Week getNextDay();
private String describe;
public String getDescribe() {
return this.describe;
}
}
public static void main(String[] args) {
Week week = Week.valueOf("MON"); // 模拟从web前端取到MON字符串
System.out.println(week.name() + " " + week.getDescribe()); //MON 周一
}
枚举类型基本的用法大致就介绍到这里,欢迎大家围观吐槽!