可动态扩展的枚举

枚举

什么是枚举?

枚举本质上是一组有限的特殊定义的数据集合。枚举常量通常用于表示一组相关的离散取值,比如颜色、星期几、方向等。

在编程中,枚举是一种更好地表达代码意图的方式,可以增加代码的可读性和可维护性。使用枚举可以将一组相关的常量进行命名,并将其组织在一个统一的类型中,这样可以避免使用硬编码的数字或字符串,减少出错的可能性。

在Java中我们如何定义枚举?

在Java中,枚举(Enum)是一种特殊的类,用于表示一组有限的、预定义的常量集合。枚举在Java语言中是一种基本数据类型,它是通过关键字**enum**来定义的。

如下:我们定义了颜色类型的枚举,包含三种颜色

// 定义一个颜色枚举类型
enum Color {
    RED,  // 红色
    GREEN,// 绿色
    BLUE; // 蓝色
}

是不是发现很简单。是的枚举的定义就是这么简单。

我们现在是思考一个问题,如果我想给这个枚举添加属性该怎么做?

比如我们定义一个日期的枚举,需要输出中文的名词,该怎么做?如下是我们定义的方式。

enum Day {
    MONDAY("星期一"),
    TUESDAY("星期二"),
    WEDNESDAY("星期三"),
    THURSDAY("星期四"),
    FRIDAY("星期五"),
    SATURDAY("星期六"),
    SUNDAY("星期日");

    private String chineseName;

    Day(String chineseName) {
        this.chineseName = chineseName;
    }

    public String getChineseName() {
        return chineseName;
    }
}

是不是发现,我们需要在枚举类 Day 中定义一个成员变量属性 chineseName,并且通过构造的方式进行赋值,并且还必须提供 getChineseName 方法,才可以获取到该枚举的属性值。

假如,我们还需要数值型的表示形式,我们就必须补充一个成员变量属性,并且提供相应的取值方法,比如:添加了一个 dayInt 属性

enum Day {
    MONDAY("星期一", 1),
    TUESDAY("星期二", 2),
    WEDNESDAY("星期三", 3),
    THURSDAY("星期四", 4),
    FRIDAY("星期五", 5),
    SATURDAY("星期六", 6),
    SUNDAY("星期日", 7);

    private String chineseName;
    private int dayInt;

    Day(String chineseName, int dayInt) {
        this.chineseName = chineseName;
				this.dayInt = dayInt;
    }

    public String getChineseName() {
        return chineseName;
    }
		public String getDayInt() {
        return dayInt;
    }
}

是不是发现,只要我们想补充属性的话,就必须添加对应的成员变量,并且补充对应的取值方法?

是不是发现这种方式不够优雅,如果我们定义很多的枚举,而且枚举都是有好几个相同的成员变量属性,我们还是必须要在每个枚举中一一进行定义?还有对应的方法?

这不是很简单嘛,java 不是可以继承嘛,我只要用一个抽象类,定义好相同的属性,子类枚举进行继承不久OK啦,哈哈哈,我真是小天才。

当你按照这样的思路去操作的时候,你会突然发现,哦呦,桥豆妈的

Java 枚举既然不支持继承???? 头皮都开了是不是?

为什么Java 枚举不能进行继承?

Java 的枚举类型是通过关键字**enum**定义的,不知道大家有没有观察过编译后的枚举类,它们在编译时被转换成一个特殊的类。而且是继承 java/lang/Enum 对象的。

如下图:

// class version 52.0 (52)
// access flags 0x4031
public final enum xxx/xxx/Day extends java/lang/Enum {
	...// 省略实际内容
}

看到了吧,final 修饰,而且java中是只能单继承的,这也就解释了为什么java中枚举不能进行继承了。

总结一下

性能:

  1. 枚举的性能非常高,因为枚举常量在类加载时就被实例化,且只会实例化一次,之后都是直接引用这些实例。
  2. 枚举类型中的常量是在编译时确定的,不需要动态创建对象,因此不会产生额外的对象创建开销。

优点:

  1. 类型安全:枚举是类型安全的,编译器会在编译时进行类型检查,确保枚举常量在声明的枚举类型范围内。
  2. 易读性和可维护性:枚举常量是有意义的命名,使得代码更加清晰易读,并且在后续的代码维护中也更加稳定可靠。
  3. 单例模式:每个枚举常量只会被实例化一次,保证了每个常量只有一个实例,可以用于实现单例模式。
  4. 线程安全:枚举类型的实例化是线程安全的,不需要额外的同步措施。

缺点:

枚举常量在编译时就确定了,无法在运行时动态添加新的常量,因此不适合表示动态变化的数据。

由于枚举中存在的局限性,还有小编在实际生产使用中遇到的问题,小编自己写了一个关于可扩展枚举的 java 工具包,欢迎大家体验。下面由小编进行介绍一下:

Extutil 工具包

关于该工具的想法来源,起初是因为在项目开发的过程中,数据库的一些状态字段经常需要用到枚举去定义,通常情况下我们会如下定义:

public enum Status {
    USE("E","E","E-在用"),
    DELETE("D","D","D-删除");

    // 当我们需要扩展属性的时候,必须先定义,而且不能通过继承的方式继承这些属性,如果在定义一个新的类 Status2 的枚举,还需要重新copy定义下面的部分
    private String name;
    private String code;
    private String desc;
    ... 省略 get set 构造方法
}

如果我们数据库定义和很多的状态,同时这些状态都规定要用枚举去定义,而且如果他们都需要 name,code,desc 三个属性,那对应的将生成很多的冗余代码,很不优雅。

这里我介绍一下关于 Extutil 包下如何使用自定义枚举

定义枚举

方式一:通用方式

这里我们通过继承抽象类 BEnum ,EUtils的bdr()方法构建自定义枚举的效果,例如:

该抽象类枚举定义了通用的三个属性 name,code,desc

其中 code 属性是唯一且必须的属性

// 通过继承 BEnum 构建自定义枚举
public class Status extends BEnum {
    public final static Status USE = EUtils.bdr("E", "E", "E-在用", Status.class);
    public final static Status DELETE = EUtils.bdr("D", "D", "D-删除", Status.class);
}

方式二:自定义扩展属性

通过 Wrappers.lambdaExpand() 的方式去扩展和自定义属性【无限扩展】

通过枚举通用的方法 apply() 获取枚举字段映射的值

public class Status extends BEnum {
   public final static Status USE = EUtils.bdr(Wrappers.lambdaExpand()
                    .ext("name","E")
                    .ext("code","E")
                    .ext("desc","E-在用")
										.ext("english","use")
										.ext("sort","1")
										.ext("remark","E-在用"), Status.class);

   public final static Status DELETE = EUtils.bdr(Wrappers.lambdaExpand()
                    .ext("code","D")
                    .ext("desc","D-删除"), Status.class);
}

// 获取枚举自定义属性的值 Status.USE.apply("字段") 
Status.USE.apply("code"); // 获取字段 code 的值,值为 E

工具类 EUtils 的使用

EUtils 工具类不仅用于枚举的定义,还提供了一些枚举的通用方法

// 获取自定义枚举类 Status 的 map 集合
 Map<String, BEnum> benumMap = EUtils.getEnumMap(Status.class)
 
 // 获取自定义枚举类 Status 的 list 集合
 List<BEnum> benumList = EUtils.getEnumList(Status.class)
 
 // 根据 code 获取 Status 对象
 Status e = EUtils.getEnumList(Status.class, "E")

Maven 库

快速开始使用体验,只需要在工程中引入以下依赖即可

<dependency>
    <groupId>cn.com.openboot</groupId>
    <artifactId>extutil-enums</artifactId>
    <version>1.0.1-beta</version>
</dependency>

源码小编已经发布到 gitee 仓库,欢迎大家关注,三人行,必有我师焉,小编一定还存在不足的地方,希望大家多给小编提提建议,大家一起进步。

gitee 地址:

openboot/extutil

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐