在 Java 运行时更改枚举

问题描述 投票:0回答:3

有什么方法可以将元素添加到Java中的内置枚举类中吗?

我的问题类似于我可以在Java运行时添加和删除枚举元素吗,但这个问题似乎是为了构建你自己的枚举然后修改它。我假设在某个地方有一个我无法更改的现有枚举,例如

enum Days{ MONDAY, TUESDAY, WEDNESDAY }

我想添加星期四、星期五等。因此不幸的是,关于如何使用接口来实现我的目标的建议,或其他比枚举更有效的方法,在这里不适用。

据我了解,枚举是隐式最终的,因此我无法扩展它并向其添加更多元素。它有私有字段,但看来我可以使用反射来访问这些字段 - 我可以更改其中一个私有字段吗,即使我无法添加新字段,即从星期一更改为星期四?

编辑:澄清情况

人们建议在将代码编译到程序中之前对其进行更改。我的代码是一个更大项目的一部分,我无法更改;在我的类访问它之前,包含枚举的类由较大的程序加载。此时,我想将缺少的元素添加到枚举中。字节码操作仍然是可行的方法吗?

java enums runtime
3个回答
7
投票

枚举旨在成为具有常量意义的静态、最终、不可变、实例控制的对象。 每当您的项目包含编译时已知的事物的自然分组或列表时,您都应该考虑使用枚举。

JVM保证枚举是实例控制的并且在运行时不可变。 枚举的二进制兼容性也得到保证,因此如果稍后添加枚举常量,您的程序将继续运行。

简短的回答是:“不,没有简单的方法可以在 Java 中扩展枚举类。”

一种替代方法是让基本枚举实现一个接口,作为枚举常量的基本类型。

然后可以通过创建实现该接口的新枚举来“扩展”枚举。 即便如此,根据设计,这并不是在运行时发生的事情。


0
投票

您可以在运行时更改枚举,方法是在加载类之前在运行时更改类。 您可以在运行时编译更改的枚举并加载它,也可以使用字节码操作来更改它。

简而言之,包含您需要的所有枚举,并且您永远不需要在运行时添加它们。 例如如果一周只有 7 天,请在编译时包含所有这些天。


0
投票

简短的回答是“从 Java 12 开始就没有”。

更长的答案是,在 Java 12 之前,您可以使用反射来扰乱枚举的特殊字段(称为

$VALUES
)的可访问性。除了使字段可访问之外,您还需要使用如下方法删除最终修饰符:

final Field field = MyEnum.getDeclaredField("$VALUES");

// make the values public
setAccessibleState(field, true);

// make the values non-final
final Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

之后你就可以随意修改

$VALUES
数组了。

然而,自 Java 12 以来,许多类在获取其声明的字段时有特定的排除,其中包括 java.lang.reflect.Field。从 Java 12 开始尝试此技巧会导致

getDeclaredField()
在这些“受保护”类之一上使用时抛出 NoSuchField 异常。

© www.soinside.com 2019 - 2024. All rights reserved.