Java学习——枚举类
摘要:本文主要介绍了Java的枚举类。
部分内容来自以下博客:
https://www.cnblogs.com/sister/p/4700702.html
https://blog.csdn.net/zhou520yue520/article/details/80952404
为什么使用枚举类
枚举类更加直观,类型安全。使用常量会有以下几个缺陷:
类型不安全。若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象。
没有命名空间。开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代表季节。
枚举类的语法
枚举类默认继承java.lang.Enum类,而不是Object类,因此枚举类不能显示继承其他父类。
使用enum定义的非抽象的枚举类默认会使用final修饰,因此非抽象枚举类不能派生子类(即不能被继承)。不过,并不是所有的枚举类都使用了final修饰,非抽象的枚举类才默认使用final修饰。对于一个抽象的枚举类(只要它包含了抽象方法,它就是抽象枚举类)而言,系统默认使用abstract修饰,而不是final。
枚举类的构造器只能使用private访问控制符,如果忽略访问控制符的话,则默认使用private修饰,如果强制指定其他的访问控制符(例如public、procted等),则会报错。
枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不可能产生实例。列出的这些实例,系统会自动给它们加上public static final修饰。枚举类的实例以逗号分隔,分号结束,这些列出的枚举值代表了该枚举类的所有可能的实例。
枚举类的用法
Switch对枚举类的扩展
switch的控制表达式(即括号中的条件)可以是任何枚举类型;当switch控制表达式使用枚举类型时,后面case表达式中的值可以直接使用枚举值的名字,而无需添加枚举类作为限定(不需要而且也不能这样写:SeasonEnum.SPRING)。
创建枚举类:
1 public enumSeasonEnum {2 SPRING, SUMMER, AUTUMN , WINTER;3 }
在switch控制表达式里使用枚举类:
1 public voidtest(SeasonEnum season) {2 switch(season) {3 caseSPRING:4 System.out.println("春天");5 break;6 caseSUMMER:7 System.out.println("夏天");8 break;9 caseAUTUMN:10 System.out.println("秋天");11 break;12 caseWINTER:13 System.out.println("冬天");14 break;15 default:16 break;17 }18 }
获取枚举类所有实例
枚举类默认有一个values()方法(不是继承来的),可以返回该枚举类的所有实例。
1 public voidtest() {2 SeasonEnum[] values =SeasonEnum.values();3 for(SeasonEnum season : values) {4 System.out.println(season);5 }6 }
枚举类的成员变量、方法和构造器
枚举类是一种特殊的类,它一样可以有自己的成员变量、方法,可以有自己的构造器,也可以实现一个或多个接口,但不能继承其他的类。
成员变量
枚举类的每个实例的成员变量的值(即对应的含义)应该是不能改变的,而且不需要使用修饰符修饰。
方法和构造器
所有成员变量都使用final修饰,则必须使用下面三种方法为成员变量指定初始值:
1. 在构造器里为这些成员变量指定初始值。
2. 在定义成员变量时指定默认值。
3. 在初始化块中指定初始值。
实际上,后面两种方式并不常用。所以,应该为枚举类显示定义带参数的构造器。一旦为枚举类显示定义了带参数的构造器,列举枚举值时就必须对应的传入参数。
1 public enumSeasonEnum {2 SPRING("春天"), SUMMER("夏天"), AUTUMN("秋天") , WINTER("冬天");3
4 String name;5
6 privateSeasonEnum(String name) {7 this.name =name;8 }9
10 public voidshowNam() {11 System.out.println(name);12 }13 }
在第一行列出所有枚举值(实例)时,实际上就是调用了构造器创建枚举类对象;只是这里不需要使用new关键字,也无需显示调用构造器罢了。
如果在定义SeasonEnum时,没有传入参数,甚至没有使用括号,那么使用的就是SeasonEnum里默认的无参构造器。
实现接口的枚举类
如果枚举类实现了接口,可以给每个实例提供不同的实现方式。
定义一个接口:
1 public interfaceFeature {2 public voidshowFeature();3 }
普通方式由枚举类实现接口的方法
由枚举类来实现接口里的方法,这种方式会导致每个枚举类的实例调用的都是同一个方法。
1 public enum SeasonEnum implementsFeature {2 SPRING("春天"), SUMMER("夏天"), AUTUMN("秋天") , WINTER("冬天");3
4 String name;5
6 privateSeasonEnum(String name) {7 this.name =name;8 }9
10 public voidshowNam() {11 System.out.println(name);12 }13
14 @Override15 public voidshowFeature() {16 System.out.println("一年四季,春夏秋冬。");17 }18 }
每个枚举类的实例各自实现不同的方法
当每个枚举实例分别实现方法时,在枚举实例调用方法时就会呈现出不同的行为方式。
上面这种在枚举值后面紧跟花括号的语法其实是创建匿名内部类的语法,花括号就是类体部分。当创建枚举类的实例时,并不是直接创建,而是相当于创建匿名子类的实例。
1 public enum SeasonEnum implementsFeature {2 SPRING("春天") {3 @Override4 public voidshowFeature() {5 System.out.println("春光明媚,鸟语花香。");6 }7 }, SUMMER("夏天") {8 @Override9 public voidshowFeature() {10 System.out.println("烈日炎炎,酷暑难耐。");11 }12 }, AUTUMN("秋天") {13 @Override14 public voidshowFeature() {15 System.out.println("秋高气爽,硕果累累。");16 }17 }, WINTER("冬天") {18 @Override19 public voidshowFeature() {20 System.out.println("寒冬腊月,冰天雪地。");21 }22 };23
24 String name;25
26 privateSeasonEnum(String name) {27 this.name =name;28 }29
30 public voidshowNam() {31 System.out.println(name);32 }33 }
抽象枚举类
抽象枚举类,就是在枚举类里定义一个抽象方法,让每个枚举类的实例分别去实现。
1 public enumSeasonEnum {2 SPRING("春天") {3 @Override4 public voidshowFeature() {5 System.out.println("春光明媚,鸟语花香。");6 }7 }, SUMMER("夏天") {8 @Override9 public voidshowFeature() {10 System.out.println("烈日炎炎,酷暑难耐。");11 }12 }, AUTUMN("秋天") {13 @Override14 public voidshowFeature() {15 System.out.println("秋高气爽,硕果累累。");16 }17 }, WINTER("冬天") {18 @Override19 public voidshowFeature() {20 System.out.println("寒冬腊月,冰天雪地。");21 }22 };23
24 String name;25
26 privateSeasonEnum(String name) {27 this.name =name;28 }29
30 public voidshowNam() {31 System.out.println(name);32 }33
34 public abstract voidshowFeature();35 }