如果你受够了如下这种写法,那么这篇文章正好适合你:
setWeek(1);
// ...
private static final int MONDAY = 1;
private static final int TUESDAY = 2;
// ...
setWeek(MONDAY);
这种方法有如下几个缺点:
- 不会进行安全检查,也就是说当传递的参数是100,它也不会报出编译错误;
- 可读性较差,类似setWeek(1)这种magic number,真是让人抓狂;
1. Enum的基本原理
针对这个问题Java
提供了解决办法,通过Enum
类型来完成,初次看到这个类型可能会有一点疑惑究竟是什么东西,和普通的类有什么不同,为了解决这个疑惑,我们首先弄清楚其中的原理,如下很简单常见枚举类型:
public enum Person{
MALE, FEMALE
}
在编译之后使用JDK
自带的javap工具进行反编译查看字节码文件,如下:
从字节码文件中看可以得到一下信息:
Enum
类型Person
实际上是继承自java.lang.Enum<Person>
的类,所以不能再继承别的类,但是可以实现接口;- 由于类被
final
修饰,所以不能再被别的类继承; - 每个枚举常量都是该类的一个实例,并且被
public static final
修饰; - 该类有两个隐式静态的方法
values()
和valueOf()
; - 还有一个静态代码段
static{}
;
从上可以看出Enum其实就是通过公有静态的字段来达到和private static final int MONDAY = 1
相同的效果。
更进一步去查看反编译生成的字节码java -p Person.class,如下:
从上面的字节码可以看出其实Enum的实现并不复杂,只是被JDK
封装的很复杂。
2. 基本使用方法
2.1 两个有用的方法
由于Enum
枚举类型是继承自java.lang.Enum<Person>
的类,所以java.lang.Enum<Person>
其中的方法也可以被使用:
- name():返回枚举常量的名称;
- ordinal():返回枚举常量在枚举声明中的位置序号,第一个常量的位置是0;
但是这里有一个问题需要说一下,不要通过枚举的序号来唯一标识一个枚举常量,因为如果顺序改变,同一个枚举常量的序号就会变化,而最好采用一个字段来和枚举常量建立联系,如下这种写法是推荐的:
public enum Person{
MALE("M"), FEMALE("F");
private String value;
Person(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
}
注意
Enum
中的构造函数不能使用public
修饰,这也暗示我们枚举类型不推荐在外部实例化
另外对于name()
方法,JDK
也不建议我们直接使用,而是通过toString()方法返回可读性性更强的name。
2.2 用于switch
一般来说在使用switch的时候第一反应是使用int
类型进行判断,但是Enum出现之后也得到了switch支持,具体使用方法如下:
public class Main{
public static void main(String[] args) {
Person person = Person.MALE;
switch (person){
case MALE:
System.out.println("male");
break;
case FEMALE:
System.out.println("male");
break;
default:
break;
}
}
public enum Person{
MALE("M"), FEMALE("F");
private String value;
Person(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
}
}
那它到底是怎么执行的呢?还是使用javap -c Main
看一下,如下:
从上我们发现,具体在底层实现的时候还是使用int
进行判断,只不过Enum
类型使用ordinal()
函数进行的转换。
2.3 隐式方法values()
通过使用values()
方法遍历其中的枚举常量,如下:
public static Person getPerson(String value){
return Arrays.asList(Person.values()).stream()
.filter(person -> value.equalsIgnoreCase(person.getValue()))
.findAny().get();
}
2.4 EnumSet
&& EnumMap
伴随着Enum的出现也相应的出现了两个集合类EnumSet
、EnumMap
,由于这两个类从没使用过,所以就不展开说了,可以看如下的相关文章。
相关文章: