目录
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 方法,小哥哥都是一样的。
*/
@Test
public void testValues() {
WeekEnum1[] values = WeekEnum1.values();
for (WeekEnum1 weekEnum1 : values) {
// Monday Tuesday Wednesday Thursday Friday Saturday Sunday
System.out.print(weekEnum1 + "\t");
}
System.out.println();
WeekEnum1[] values1 = WeekEnum1.Sunday.values();
for (WeekEnum1 weekEnum1 : values1) {
// Monday Tuesday Wednesday Thursday Friday Saturday Sunday
System.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 Integer code;
private 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 Integer code;
private String name;
/**
* 构造器默认是 private ,外部无法 new 枚举对象,只能通过上面的常量获取实例,必须与枚举参数对应
*
* @param code
* @param name
*/
WeekEnum3(Integer code, String name) {
this.code = code;
this.name = name;
}
@Override
public Integer getCode() {
return this.code;
}
@Override
public String getName() {
return this.name;
}
/**
* 将整个枚举参数转为 Map 结构
*
* @return
*/
@Override
public 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, "星期一") {
@Override
public String toSplitString() {
return Monday.code + "," + Monday.name;
}
},
Tuesday(2, "星期二") {
@Override
public String toSplitString() {
return Tuesday.getCode() + "," + Tuesday.getName();
}
};
/**
* 属性名称可以随便取,但是构造器中的参数类型必须与上面的枚举参数类型对应
*/
private Integer code;
private 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 String code;
private 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 String code;
private 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.
*/
@Test
public 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 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。