Java 枚举(enum)剖析
目录
Java 枚举(enum)概述
枚举常量 & values 遍历
枚举属性、方法、参数
枚举实现接口
枚举定义抽象方法、静态方法
同一工具类中维护多个枚举
switch case 枚举
枚举创建单例
Java 枚举(enum)概述
1、Java JDK 1.5 新增的 enum 关键词,可以定义枚举类,如 public enum WeekEnum { }.
2、使用 enum 定义后的枚举类在编译后默认继承 java.lang.Enum 类,而不是普通的继承 Object 类。由于 Java 不支持多继承,所以枚举不能再显示的继承其他类,但是可以实现接口。
3、Enum 类默认实现了 Java.lang.Comparable 接口与 Serializable 接口。
4、enum 声明后,该类会被编译器加上 final 声明(如同 String),故枚举无法被继承。
5、枚举类内部定义的枚举值就是该类的实例,且必须在第一行定义,当类初始化时,这些枚举值会被实例化,互相以逗号分隔。 如 "Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday"。
6、枚举规定好了指定的取值范围,所有的内容只能从指定的范围中取得。
7、枚举是一种类型,用于定义变量,以限制变量的赋值;通过 "枚举名.值" 取得枚举值,每个值都是一个 Enum 实例。
8、枚举是一个特殊的类,可以定义自己的 field(包括静态属性)、方法(包括静态方法)、可以实现接口,也可以定义自己的构造器。
9、枚举类的构造方法默认用 private 修饰的,且不能出现 public 构造方法,因此无法 new 一个枚举对象。
10、实际编程中往往存在着这样的 "数据集",它们的数值是稳定的、元素个数是有限的,例如星期一到星期日,春夏秋冬四季等等,很多时候大家选择使用常量。 JDK 1.5 开始有了枚举,其实可以把相关的常量放到一个枚举类型里,枚举提供了比常量更多的方法,使用起来更加方便。
枚举的构造器私有,每一个枚举值都是一个枚举实例,编译后自动产生。 枚举值的参数与构造器的参数相对应: 枚举值后面没跟参数时,对应构造器的无参构造, |
枚举编译构建实例顺序:枚举值后面的实参值->找到对应的构造方法->注入给相应的成员变量。因为构造器可以重载,所以枚举值后面的参数可以不同,包括类型与个数。 |
每个枚举值既可以调用自己独有的属性,即后面的参数值,也可以调用公共的属性,即可调用自己下面独有的方法,也可调用公共的方法。 |
当枚举值/枚举常量没有带参数时,则没必要构造器,反之如果枚举值有参数,则必须有构造器与之对应。 |
方法 | 描述 |
---|---|
toString | Enum 类重写了 toString 方法,返回枚举常量名。 |
values | 每个枚举类都有一个 values 方法,该方法可以遍历枚举类的所有实例. |
static Enum valueOf(Class enumClass, String name) | 返回指定名字、给定类的枚举常量 |
boolean equals(Object other) | 比较枚举是否相等。也可以直接使用 == 比较是否相等。 |
枚举常量 & values 遍历
1、定义枚举。
public enum WeekEnum1 {/*** 最简单的枚举形式,使用逗号分隔,结尾分号此时可以省略* 每一个值都代表当前的枚举实例,通过 枚举名.值 获取*/Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
/*** 每个枚举类都有一个 values 方法,该方法可以遍历枚举类的所有实例.* 1、可以直接通过类名调用 values 方法,小哥哥都是一样的。* 2、也可以通过枚举常量调用 values 方法,小哥哥都是一样的。*/@Testpublic void testValues() {WeekEnum1[] values = WeekEnum1.values();for (WeekEnum1 weekEnum1 : values) {// Monday Tuesday Wednesday Thursday Friday Saturday SundaySystem.out.print(weekEnum1 + "\t");}System.out.println();WeekEnum1[] values1 = WeekEnum1.Sunday.values();for (WeekEnum1 weekEnum1 : values1) {// Monday Tuesday Wednesday Thursday Friday Saturday SundaySystem.out.print(weekEnum1 + "\t");}}
src/main/java/org/example/enums/WeekEnum1.java · 汪少棠/java-se - Gitee.com
测试枚举:src/main/java/org/example/enums/WeekEnumTest1.java · 汪少棠/java-se - Gitee.com
枚举属性、方法、参数
1、枚举像普通的类一样可以添加属性和方法(包括静态或非静态的属性或方法)。注意枚举值要写在最前面,且以分号结尾,否则编译出错。
2、枚举常量后面可以接括号定义枚举参数,这些参数会通过对应的构造器自动给属性赋值。"枚举参数 -> 对应的构造器 -> 属性" 完成赋值。
public enum WeekEnum2 {/*** 枚举值写在最前面,有其他内容时,必须以分号结尾。* 因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应* 匹配两个参数的构造器创建 1-6 实例* 匹配三个参数的构造器创建 Sunday 实例*/Monday(1, "星期一"),Tuesday(2, "星期二"),Wednesday(3, "星期三"),Thursday(4, "星期四"),Friday(5, "星期五"),Saturday(6, "星期六"),Sunday(7, "星期天", "周末");/*** 属性名称可以随便取,只需要构造器中的参数类型必须与上面的枚举参数类型对应*/private final Integer code;private final String name;private String ext;/*** 支持定义静态属性*/public static String summary;/*** 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应** @param code* @param name*/WeekEnum2(Integer code, String name) {this.code = code;this.name = name;}WeekEnum2(Integer code, String name, String ext) {this.code = code;this.name = name;this.ext = ext;}/*** 因为枚举常量的参数都是通过内部私有的构造器赋值的,无法通过外部赋值,所以没必要提供 setter方法* 但是可以提供 getter 方法来获取枚举参数值** @return*/public Integer getCode() {return code;}public String getName() {return name;}public String getExt() {return ext;}/*** 获取工作日 周一到周五-----支持静态方法** @return*/public static Set<WeekEnum2> getWorkDays() {Set<WeekEnum2> workDays = new HashSet<>(5);workDays.add(WeekEnum2.Monday);workDays.add(WeekEnum2.Tuesday);workDays.add(WeekEnum2.Wednesday);workDays.add(WeekEnum2.Thursday);workDays.add(WeekEnum2.Friday);return workDays;}/*** 根据 星期数字获取对应的星期中文** @param code 星期几 [1,7]* @return :返回中文,星期一、星期二、...*/public static WeekEnum2 getWorkDayByCode(Integer code) {WeekEnum2[] values = WeekEnum2.values();for (WeekEnum2 value : values) {if (StrUtil.equals(String.valueOf(value.code), String.valueOf(code))) {return value;}}return null;}
}
src/main/java/org/example/enums/WeekEnum2.java · 汪少棠/java-se - Gitee.com
src/main/java/org/example/enums/WeekEnum2Test.java · 汪少棠/java-se - Gitee.com
枚举实现接口
1、先准备一个接口:
import java.util.Map;
public interface WeekEnumInterface {Integer getCode();String getName();Map<String, Object> getDataMap();
}
src/main/java/org/example/enums/WeekEnum3Interface.java · 汪少棠/java-se - Gitee.com
2、定义枚举并实现接口
public enum WeekEnum3 implements WeekEnum3Interface {//枚举值写在最前面,有其他内容时,必须以分号结尾。//因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应//匹配两个参数的构造器创建实例Monday(1, "星期一"),Tuesday(2, "星期二"),Wednesday(3, "星期三"),Thursday(4, "星期四"),Friday(5, "星期五"),Saturday(6, "星期六"),Sunday(7, "星期天");/*** 属性名称可以随便取,但是构造器中的参数类型必须与上面的枚举参数类型对应*/private final Integer code;private final String name;/*** 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应** @param code* @param name*/WeekEnum3(Integer code, String name) {this.code = code;this.name = name;}@Overridepublic Integer getCode() {return this.code;}@Overridepublic String getName() {return this.name;}/*** 将整个枚举参数转为 Map 结构** @return*/@Overridepublic Map<String, Object> getDataMap() {Map<String, Object> dataMap = new HashMap<>(WeekEnum3.values().length);for (WeekEnum3 weekEnum : WeekEnum3.values()) {dataMap.put(weekEnum.code + "", weekEnum.name);}return dataMap;}
}
src/main/java/org/example/enums/WeekEnum3.java · 汪少棠/java-se - Gitee.com
测试代码:
src/main/java/org/example/enums/WeekEnum3Test.java · 汪少棠/java-se - Gitee.com
枚举定义抽象方法、静态方法
1、枚举中可以有抽象方法,且由枚举值/枚举常量提供方法实现。枚举类如下:
public enum WeekEnum4 {/*** 枚举值写在最前面,有其他内容时,必须以分号结尾。* 因为枚举只能通过常量获取枚举实例,所以枚举参数必须与构造器中的参数对应*/Monday(1, "星期一") {@Overridepublic String toSplitString() {return Monday.code + "," + Monday.name;}},Tuesday(2, "星期二") {@Overridepublic String toSplitString() {return Tuesday.getCode() + "," + Tuesday.getName();}};/*** 属性名称可以随便取,但是构造器中的参数类型必须与上面的枚举参数类型对应*/private final Integer code;private final String name;/*** 全部枚举值放入到常量中* 在静态代码块中为其赋值*/private static final Map<Integer, WeekEnum4> weekEnum4Map = new HashMap<>();static {for (WeekEnum4 weekEnum4 : values()) {weekEnum4Map.put(weekEnum4.getCode(), weekEnum4);}}/*** 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应** @param code* @param name*/WeekEnum4(Integer code, String name) {this.code = code;this.name = name;}public Integer getCode() {return code;}public String getName() {return name;}/*** 方法要是 public 修饰外部才能调用** @return*/public abstract String toSplitString();/*** 根据数字获取星期枚举* 静态方法,方便通过类名调用。** @param index* @return*/public static WeekEnum4 of(Integer index) {return weekEnum4Map.get(index);}/*** 获取全部枚举项** @return*/public static List<WeekEnum4> list() {WeekEnum4[] values1 = WeekEnum4.values();ArrayList<WeekEnum4> weekEnum4s = Lists.newArrayList(values1);return weekEnum4s;}
}
测试代码:src/main/java/org/example/enums/WeekEnum4Test.java · 汪少棠/java-se - Gitee.com
同一工具类中维护多个枚举
public class EnumComm {/*** 红绿灯颜色枚举*/public enum ColorEnum {Red("red", "红色"),Yellow("yellow", "黄色"),Green("green", "绿色");private final String code;private final String name;ColorEnum(String code, String name) {this.code = code;this.name = name;}public String getCode() {return code;}public String getName() {return name;}}/*** 系统上线省份枚举*/public enum AreaEnum {HuNan("43", "湖南"),HeNan("41", "河南"),LiaoNiang("21", "辽宁");private final String code;private final String name;AreaEnum(String code, String name) {this.code = code;this.name = name;}public String getCode() {return code;}public String getName() {return name;}}
}
src/main/java/org/example/enums/EnumComm.java · 汪少棠/java-se - Gitee.com
src/main/java/org/example/enums/EnumCommTest.java · 汪少棠/java-se - Gitee.com
src/main/java/org/example/enums/EscalationConsts.java · 汪少棠/java-se - Gitee.com
switch case 枚举
/*** 枚举作为 switch (xxx) 参数时,case 中的值必须是枚举常量的非限定名称。* 不能是 枚举.常量 的方式,否则编译不通过:* An enum switch case label must be the unqualified name of an enumeration constant.*/@Testpublic void testSwitchCase() {WeekEnum2 workDayByCode = WeekEnum2.getWorkDayByCode(9);switch (workDayByCode) {// 这种方式是编译不通过的,必须是非限定名称// case WeekEnum2.Monday:case Monday:System.out.println(workDayByCode.getCode());break;case Saturday:System.out.println(workDayByCode.getName());break;case Sunday:System.out.println(workDayByCode.getExt());break;default:System.out.println(workDayByCode);break;}}
src/main/java/org/example/enums/WeekEnum2Test.java · 汪少棠/java-se - Gitee.com
枚举创建单例
/*** 枚举创建单例** @author wangMaoXiong* @version 1.0* @date 2022/12/16 14:30*/
public class Person {private String agencyCode;private String idenNo;private String idenType;private String perName;private String sexCode;private String control;/*** 私有化构造函数*/private Person() {}private enum SingletonEnum {/*** 枚举类内部定义的枚举值就是该类的实例,必须在第一行定义,当类初始化时,这些枚举值会被实例化.* 创建一个枚举对象,该对象天生为单例。* 枚举INSTANCE会在类加载初始化的时候创建,而Java类的加载和初始化过程都是线程安全的。*/INSTANCE;/*** 枚举是一个特殊的类,可以定义自己的 field(包括静态属性)、方法(包括静态方法)、可以实现接口,也可以定义自己的构造器。*/private final Person person;/*** 枚举类的构造方法默认用 private 修饰的,且不能出现 public 构造方法,因此无法 new 一个枚举对象。*/SingletonEnum() {person = new Person();}public Person getInstance() {return person;}}/*** 对外暴露一个获取单例对象的静态方法** @return*/public static Person getInstance() {return SingletonEnum.INSTANCE.getInstance();}// 省略 getter、setter、toString 方法
}
src/main/java/org/example/enums/Person.java · 汪少棠/java-se - Gitee.com。
src/main/java/org/example/enums/PersonTest.java · 汪少棠/java-se - Gitee.com。