在 Java 中扩展枚举
本文介绍如何在 Java 中扩展枚举功能。
在 Java 中扩展枚举
我们可以将枚举视为一种编译器魔法,因为在字节码中,枚举表示为具有多个静态成员的类,并且继承自抽象 java.lang.Enum。
这就是枚举不能扩展任何其他类或枚举的原因。 正如我们无法在 Java 中扩展枚举一样,任何类也不可能扩展枚举。 让我们使用以下示例代码来学习,看看会发生什么。
示例代码:
package jiyik;
enum Cars {Audi, BMW, Marcedes}
public class Example extends Cars {
public static void main(String... args) {
}
}
上面的代码有一个名为 Cars 的枚举,Example 类正在尝试扩展它。 查看输出:
/Example.java:5: error: cannot inherit from final Cars
public class Example extends Cars {
^
/Example.java:5: error: enum types are not extensible
public class Example extends Cars {
^
2 errors
正如我们所看到的,类不能扩展枚举。 那么如果无法扩展枚举,我们还能扩展它的功能吗?
功能可以定义为枚举中实现的方法。 例如,上面代码中的枚举 Cars 可以为每个成员声明抽象方法; 参见示例:
enum Cars {
Audi { @Override public void drive() { } },
BMW { @Override public void drive() { } },
Mercedes { @Override public void drive() { } },
;
public abstract void drive();
}
正如我们所看到的,每个成员都可以重写drive()方法。 但不幸的是,并不总是可以在枚举中创建方法,因为:
- 如果枚举属于第三方库或其他团队,则它将不允许实现抽象方法。
- 如果它属于不具有drive()方法所需的依赖项的模块。
- 如果枚举被其他函数和数据重载,它将变得不可读。
提供了一些解决方案可以解决这些问题并扩展 Java 中枚举的功能。
解决方案1:Java中的镜像枚举
顾名思义,我们需要使用相同的数据创建另一个枚举。 这个新的枚举也将实现drive()方法,所以我们现在有两个枚举:
枚举 Cars 的示例代码:
enum Cars {
Audi { @Override public void drive() { } },
BMW { @Override public void drive() { } },
Mercedes { @Override public void drive() { } },
;
public abstract void drive();
}
枚举 DriveCars 的示例代码:
enum DriveCars {
Audi { @Override public void drive() { } },
BMW { @Override public void drive() { } },
Mercedes { @Override public void drive() { } },
;
public abstract void drive();
}
第二个枚举是第一个枚举的镜像。 现在我们可以通过扩展功能来使用这两个枚举; 我们需要使用内置枚举方法 name()
和 valueof()
。
请参阅以下示例了解如何使用它:
Cars cars = ...
DriveCars.valueOf(cars.name()).drive();
上面的代码显示了如何在枚举 DriveCars 中使用枚举 Cars 功能。 这意味着功能得到了扩展。
上面代码中的 name()
方法是final的,不能被重写,而valueOf方法将由编译器生成。 这两种方法非常适合,在扩展操作中不会出现功能错误。
上面的代码有一个问题,如果枚举Cars改变了,枚举DriveCars将不知道任何想法,并且会导致trick的名称和值失败。 为了解决这个问题,我们必须让DriveCars知道它的父镜像是Cars。
为此,我们可以使用静态初始化程序来比较 DriveCars 和 Cars,如果两个枚举不匹配,则会抛出异常。 这是 enumus 库中的一个示例:
enum DriveCars {
....
static {
Mirror.of(Cars.class);
}
}
该实用程序类将检查两个枚举是否匹配。 此方法将验证 name() 和 valueOf() 技巧。
解决方案 2:Java 中的映射枚举
如果您不想创建另一个仅包含一种方法的枚举。 在这种情况下,我们可以使用接口来代替枚举; 请参见下面的示例:
public interface Driver {
void drive();
}
现在要使用此接口 Drive 和枚举 Cars,我们可以在它们之间创建映射。 这是地图的示例:
Map<Cars, Driver> drivers = new EnumMap<>(Cars.class) {{
put(Audi, new Driver() { @Override public void driver(){}})
put(BMW, new Driver() { @Override public void driver(){}})
put(Mercedes, new Driver() { @Override public void driver(){}})
}}
现在要使用它们,请使用这段简单的代码:
drivers.get(Cars).drive();
上面代码中使用的 EnumMap 将保证每个枚举成员仅出现一次,但它不保证每个成员都有一个条目。
我们可以检查映射的大小是否等于枚举成员的数量:
drivers.size() == Cars.values().length
enumus 库还为这种情况提供了一个实用程序:如果地图不适合汽车,它将抛出 IllegalStateException。 这是实用程序:
EnumMapValidator.validateValues(Cars.class, map, "Cars map");
上述两种方法都展示了如何通过扩展枚举的功能来使枚举变得强大。 虽然不可能直接扩展枚举,但我们可以使用这些技巧来扩展它们的功能。
相关文章
在 Java 中将 Enum 转换为 Int
发布时间:2023/07/20 浏览次数:192 分类:Java
-
本文介绍如何在 Java 中将 Enum 转换为 Int。在 Java 中将 Enum 转换为 Int Java 不提供将 enum 转换为 int 或反之亦然的内置功能,但我们可以创建方法来执行这些操作。 我们可以使用 value() 方法将具有
在 Java 中声明枚举
发布时间:2023/07/20 浏览次数:89 分类:Java
-
在 Java 中声明 DownloadType 的枚举将是本文讨论的主题。 让我们首先看看枚举的用途。Java 中枚举的用途
Java 中的静态枚举与非静态枚举
发布时间:2023/07/20 浏览次数:173 分类:Java
-
本文介绍了Java中的枚举以及静态和非静态枚举的区别。Java 中的 Enum 简介 在 Java 中,枚举是一种数据类型,程序员可以使用它来创建多个常量变量。
Java 中的罗马数字
发布时间:2023/07/19 浏览次数:182 分类:Java
-
本文介绍如何在 Java 中将整数转换为罗马数字。Java 中的罗马数字 在 Java 中工作时经常需要将整数转换为罗马数字。
从Java中的链表中删除节点
发布时间:2023/07/19 浏览次数:85 分类:Java
-
本文介绍如何在 Java 中从链表中删除节点。从Java中的链表中删除节点 链表是Java的util包中的一种数据结构,它实现了链表数据结构
Java 中的自定义帮助器方法
发布时间:2023/07/19 浏览次数:177 分类:Java
-
我们创建一个帮助器类来帮助提供不是实现或实现它的类的主要目标的功能。简而言之,辅助对象是辅助类的实例。 在委托模式中,使用了相同的辅助对象。该演示将通过从头开始向您展示实
使用Java中的wait()和notify()方法
发布时间:2023/07/19 浏览次数:127 分类:Java
-
本文介绍了 Java 中的 wait() 和 notification() 方法。使用Java中的wait()和notify()方法 wait() 和 notify() 方法提供了一种允许线程等待直到满足特定条件的机制。 例如,当您想要为某些固定大小的元素后
Java Streams 中的flush()方法的使用
发布时间:2023/07/19 浏览次数:136 分类:Java
-
本文将讨论Java流中的 flush() 函数及其主要用途。Java中的flush()方法 该 Writer 流可以使用 flash() 函数进行刷新,该函数可以在 Writer 类中找到。
Java 中的重写和重载静态方法
发布时间:2023/07/19 浏览次数:156 分类:Java
-
在本文中,我们将讨论 Java 中是否可以覆盖和重载静态方法。 但在我们进一步讨论之前,让我们先明确几个关键点:Java 面向对象的本质使得重写和重载变得至关重要。 当程序员需要多功能性