背景:
在工作中我们都会创建一些静态常量,例如:
// 春天
private static final String SPRING = 1;
这种定义方式看似十分简单,但是其实是存在很多问题的:
- 就是在使用过程中,别的开发人员会把你定义的常量用作别的用途,比如上面可能会被用作与别的数相加等等;
所以这个时候就需要就需要使用枚举,java5新增了enum关键字(它与calss、interface关键字的地位相同),用于定义枚举类。枚举类是一个特殊的类,它一样可以有自己的成员变量、方法,可以实现一个或多个接口,也可以定义自己的构造器。一个java源文件最多只能定义一个public访问权限的枚举类,且该java源文件也必须和该枚举类的类名相同。
枚举和普通类的区别:
- 枚举类可以实现一个或多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是默认继承Object类,因此枚举类不能显式继承其他父类。其中
java.lang.Enum
类实现了java.lang.Serializable
和java.lang.Comparable
两个接口。 - 使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类。
- 枚举类的构造器只能使用private访问控制器,如果省略了构造器的访问控制符,则默认使用private修饰;如果强制指定访问控制符,则只能指定
private
修饰符; - 枚举类的所有实例必须在枚举类的第一行显式列出,否则这个枚举类永远都不能产生实例。列出这些实例时,系统会自动添加
public static final
修饰,无须程序员显示添加;
枚举类入门:
public enum SeasonsEnum {
// 使用构造器创建对象
SPRING("春天"), SUMMER("夏天"), FALL("秋天"), WINTER("冬天");
private final String name;
// 枚举的构造器只能使用private修饰
private SeasonsEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
上面的程序中,在第一行中显式的列出枚举值,其中SPRING("春天")
是调用构造器创建枚举类对象,只是这里无须new
关键字,也无须显示调用构造器。因为这里的构造器是含有参数的,所以必须传入一个参数;其实,SPRING("春天")
实际上等同于下面的代码:
private static final SeasonsEnum SPRING = new SeasonsEnum("春天");
实现接口的枚举类
枚举类也可以实现一个或者多个接口,与普通实现一个或多个接口完全一样,枚举类实现一个或多个接口,也需要实现该接口所包含的方法。
// 枚举类接口
public interface EnumInterface {
public void say();
}
// 实现接口的枚举类
public enum SeasonsEnum implements EnumInterface{
SPRING("春天"), SUMMER("夏天"), FALL("秋天"), WINTER("冬天");
private final String name;
SeasonsEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void say() {
System.out.println("枚举类");
}
}
上面这种实现接口方式,SeasonsEnum.XXXX.say();
最终的调用结果都是调用统一的say方法,所以如果想要每个枚举值调用不同发say()方法,就需要在枚举值后面加上花括号,例如:
public enum SeasonsEnum implements EnumInterface{
SPRING("春天"){
public void say(){
System.out.println("我是春天");
}
}, SUMMER("夏天"){
public void say(){
System.out.println("我是夏天");
}
}, FALL("秋天"){
public void say(){
System.out.println("我是秋天");
}
}, WINTER("冬天"){
public void say(){
System.out.println("我是冬天");
}
};
private final String name;
SeasonsEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
这样的话,调用SeasonsEnum.SPRING.say();
输入的就是‘我是春天’
;编译上面的文件会产生5个class文件,其实SeasonsEnum对应一个文件,它的4个匿名内部子类分别各对应一个class文件;
含抽象方法的枚举类
上面我们说过非抽象的枚举类默认使用final
修饰。那么当枚举类中包含抽象方法,它就是抽象类,系统会默认使用abstract
修饰,而不是final
;
public enum SeasonEnum {
SPRING("春天"){
public void say(){
System.out.println("this is spring");
}
}, SUMMER("夏天"){
public void say(){
System.out.println("this is summer");
}
}, FALL("秋天"){
public void say(){
System.out.println("this is summer");
}
}, WINTER("冬天"){
public void say(){
System.out.println("this is winter");
}
};
private final String name;
SeasonEnum(String name) {
this.name = name;
}
public String getName() {
return name;
}
public abstract void say();
}