25.java枚举
1、概念
enum
的全称为 enumeration, 是 JDK 1.5 中引入的新特性。
枚举是一种语法糖,编译到字节码后是一个类继承 java.lang.Enum,而枚举值是静态final成员变量
在Java中,被 enum
关键字修饰的类型就是枚举类型。形式如下:
enum Color { RED, GREEN, BLUE }
如果枚举不添加任何方法,枚举值默认为从0开始的有序数值。以 Color 枚举类型举例,它的枚举常量依次为 RED:0,GREEN:1,BLUE:2
。
枚举的好处:可以将常量组织起来,统一进行管理。
枚举的典型应用场景:错误码、状态机等。
- 枚举类型的本质:除了不能继承,基本上可以将
enum
看做一个常规的类。
2、Enum抽象类
尽管 enum
看起来像是一种新的数据类型,事实上,enum是一种受限制的类,并且具有自己的方法。
创建enum时,编译器会为你生成一个相关的类,这个类继承自 java.lang.Enum
。
Enum是所有 Java 语言枚举类型的公共基本类(注意Enum是抽象类),以下是它的常见方法:
返回类型 | 方法名称 | 方法说明 |
---|---|---|
int |
compareTo(E o) |
比较此枚举与指定对象的顺序 |
boolean |
equals(Object other) |
当指定对象等于此枚举常量时,返回 true。 |
Class<?> |
getDeclaringClass() |
返回与此枚举常量的枚举类型相对应的 Class 对象 |
String |
name() |
返回此枚举常量的名称,在其枚举声明中对其进行声明 |
int |
ordinal() |
返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零) |
String |
toString() |
返回枚举常量的名称,它包含在声明中 |
static<T extends Enum<T>> T |
static valueOf(Class<T> enumType, String name) |
返回带指定名称的指定枚举类型的枚举常量。 |
构造方法:
Modifier | Constructor and Description |
---|---|
protected |
Enum(String name, int ordinal) 唯一的构造函数。 |
3、原始的接口定义常量
在JDK1.5 之前,在Java中定义常量都是public static final TYPE A;
或者接口中定义常量:
public interface DayConstant {
int MONDAY = 1;
int TUESDAY = 2;
int WEDNESDAY = 3;
int THURSDAY = 4;
int FRIDAY = 5;
int SATURDAY = 6;
int SUNDAY = 7;
}
有了枚举,你可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法
4、语法
创建枚举类型要使用 enum 关键字,隐含了所创建的类型都是 java.lang.Enum 类的子类(java.lang.Enum 是一个抽象类)。枚举类型符合通用模式 Class Enum<E extends Enum<E>>
,而 E
表示枚举类型的名称。
枚举类型的每一个值都将映射到 protected Enum(String name, int ordinal)
构造函数中,在这里,每个值的名称都被转换成一个字符串,并且序数设置表示了此设置被创建的顺序。
定义:
public enum DayEnum {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
注意:
1、值一般是大写的字母,多个值之间以逗号分隔。
2、枚举类型可以像类(class)类型一样,定义为一个单独的文件,当然也可以定义在其他类内部
使用:
public class App {
public static void main(String[] args) {
DayEnum[] values = DayEnum.values();
for (DayEnum value : values) {
System.out.println(value.ordinal()+":"+value.name());
}
}
}
values()方法的作用就是获取枚举类中的所有变量,并作为数组返回
valueOf(String name)方法与Enum类中的valueOf方法的作用类似根据名称获取枚举变量,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法
结果:
0:MONDAY
1:TUESDAY
2:WEDNESDAY
3:THURSDAY
4:FRIDAY
5:SATURDAY
6:SUNDAY
反编译查看如下:
javap DayEnum
public final class com.woniuxy.DayEnum extends java.lang.Enum<com.woniuxy.DayEnum> {
public static final com.woniuxy.DayEnum MONDAY;
public static final com.woniuxy.DayEnum TUESDAY;
public static final com.woniuxy.DayEnum WEDNESDAY;
public static final com.woniuxy.DayEnum THURSDAY;
public static final com.woniuxy.DayEnum FRIDAY;
public static final com.woniuxy.DayEnum SATURDAY;
public static final com.woniuxy.DayEnum SUNDAY;
public static com.woniuxy.DayEnum[] values();
public static com.woniuxy.DayEnum valueOf(java.lang.String);
static {};
}
1、创建enum时,编译器会为你生成一个相关的类DayEnum,这个类继承自 java.lang.Enum。
2、每个枚举变量都是枚举类DayEnum的实例,相当于MONDAY = new DayEnum(“MONDAY”, 0),按序号来。
3、每个成员变量都是final static修饰,也就是常量,常量命令规则要求全部大写
CFR反编译(了解)
java -jar cfr-0.152.jar D:\workspace\idea\day0910\target\classes\com\woniuxy\DayEnum.class --sugarenums false
参数--sugerenums false表示会解析枚举语法糖
//反编译DayEnum.class
final class DayEnum extends Enum
{
//编译器为我们添加的静态的values()方法
public static DayEnum[] values()
{
return (DayEnum[])$VALUES.clone();
}
//编译器为我们添加的静态的valueOf()方法,注意间接调用了Enum也类的valueOf方法
public static DayEnum valueOf(String s)
{
return (DayEnum)Enum.valueOf(com/woniuxy/enumdemo/DayEnum, s);
}
//私有构造函数
private DayEnum(String s, int i)
{
//调用父类Enum的构造方法
super(s, i);
}
//前面定义的7种枚举实例
public static final DayEnum MONDAY;
public static final DayEnum TUESDAY;
public static final DayEnum WEDNESDAY;
public static final DayEnum THURSDAY;
public static final DayEnum FRIDAY;
public static final DayEnum SATURDAY;
public static final DayEnum SUNDAY;
private static final DayEnum $VALUES[];
static
{
//实例化枚举实例
MONDAY = new DayEnum("MONDAY", 0);
TUESDAY = new DayEnum("TUESDAY", 1);
WEDNESDAY = new DDayEnumay("WEDNESDAY", 2);
THURSDAY = new DayEnum("THURSDAY", 3);
FRIDAY = new DayEnum("FRIDAY", 4);
SATURDAY = new DayEnum("SATURDAY", 5);
SUNDAY = new DayEnum("SUNDAY", 6);
$VALUES = (new DayEnum[] {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY
});
}
}
4、枚举的进阶用法
在前面的分析中,我们都是基于简单枚举类型的定义,也就是在定义枚举时只定义了枚举实例类型,并没定义方法或者成员变量,实际上使用关键字enum定义的枚举类,除了不能使用继承(因为编译器会自动为我们继承Enum抽象类而Java只支持单继承,因此枚举类是无法手动实现继承的),可以把enum类当成常规类,也就是说我们可以向enum类中添加方法和变量,甚至是mian方法。
Java 语法中却不允许使用赋值符号 = 为枚举常量赋值,但枚举可以添加普通方法、静态方法、抽象方法、构造方法
public enum DayEnum {
MONDAY(1001, "monday"),
TUESDAY(1002, "tuesday"),
WEDNESDAY(1003, "wednesday"),
THURSDAY(1004, "thursday"),
FRIDAY(1005, "friday"),
SATURDAY(1006, "saturday"),
SUNDAY(1007, "sunday");//加上分号,否则报错
private int code;
private String message;
DayEnum(int code, String message) {
this.code = code;
this.message = message;
}
public int getCode() {
return code;
}
public String getMessage() {
return message;
}
@Override
public String toString() {
return "DayEnum{" +
"code=" + code +
", message='" + message + '\'' +
'}';
}
}
注意:
1、如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。
2、在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。
测试调用:
public class App {
public static void main(String[] args) {
DayEnum[] values = DayEnum.values();
for (DayEnum day : values) {
System.out.println(day.getCode()+":"+day.getMessage());
}
}
}
打印结果:
1001:monday
1002:tuesday
1003:wednesday
1004:thursday
1005:friday
1006:saturday
1007:sunday
5、应用案例:
错误码(常用):
package com.woniuxy.wms.util;
/**
* @author :fengSir
* @date :Created By 2023-06-30 10:40
* @description :服务状态码
*/
public enum ServerCode {
//自定义的状态码
ERR_BAD_REQUEST(400, "请求参数格式错误"),
ERR_UNAUTHORIZED(401, "未授权登录"),
ERR_FORBIDDEN(403, "无权限访问"),
ERR_NOT_FOUND(404, "相关资源或数据不存在"),
ERR_CONFLICT(409, "数据冲突"),
ERR_INSERT(5001, "插入数据时的错误"),
ERR_DELETE(5002, "删除数据时的错误"),
ERR_UPDATE(5003, "修改数据时的错误"),
ERR_INTERNAL_SERVER_ERROR(500, "服务器内部错误"),
ERR_JWT_PARSE(6000, "解析jwt失败:格式错误,或签名错误"),
ERR_JWT_EXPIRED(6001, "解析jwt失败:过期"),
MONITOR_EXCEPTION(304, "文件监控异常");
//错误码
private final Integer code;
//提示信息
private final String message;
//构造函数
ServerCode(Integer code, String message) {
this.code = code;
this.message = message;
}
//获取状态码
public Integer getCode() {
return code;
}
//获取提示信息
public String getMessage() {
return message;
}
}
自定义属性声明为final类型的,因为枚举定义完之后不能修改
不要提供setter方法
服务器返回前端
Result.error(ServiceCode.ERR_FORBIDDEN)
状态机(了解):
我们经常使用switch语句来写状态机。JDK7以后,switch已经支持 int
、char
、String
、enum
类型的参数。这几种类型的参数比较起来,使用枚举的switch代码更具有可读性。
enum Signal {RED, YELLOW, GREEN}
public static String getTrafficInstruct(Signal signal) {
String instruct = "信号灯故障";
switch (signal) {
case RED:
instruct = "红灯停";
break;
case YELLOW:
instruct = "黄灯请注意";
break;
case GREEN:
instruct = "绿灯行";
break;
default:
break;
}
return instruct;
}
注意:不能在switch()括号中直接写Signal类名,必须是Signal的变量名称signal
6、总结
- enum是一种受限制的类,并且具有自己的方法
- 声明使用enum关键字,声明的枚举默认继承自
java.lang.Enum
- 枚举可以声明一个独立的文件(常见),也可以声明在一个类中(不常见)
- 枚举成员全部大写,每个成员其实是枚举对应类的实例,每个实例调用
java.lang.Enum
中的Enum(String name, int ordinal)
唯一的构造函数,并且该实例为public static final
修饰,因为是常量,所以要求全部大写。 - 枚举中可以添加属性,并可以生成set方法,(get方法一般用不到,因为枚举成员是常量,只能被赋值一次,并在创建时就赋值了)
- 枚举可以添加普通方法、静态方法、抽象方法、构造方法,
- 在添加属性或方法时,枚举成员必须是首先声明,且枚举成员最后一位加上分号
- 开发过程用使用比较多的场景就是作为错误码传值返回给前台
本文来自博客园,作者:icui4cu,转载请注明原文链接:https://www.cnblogs.com/icui4cu/p/18872900