我可以在运行时在 Java 中添加和删除枚举元素吗
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/478403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can I add and remove elements of enumeration at runtime in Java
提问by brabster
It is possible to add and remove elements from an enum in Java at runtime?
可以在运行时从 Java 中的枚举中添加和删除元素吗?
For example, could I read in the labels and constructor arguments of an enum from a file?
例如,我可以从文件中读取枚举的标签和构造函数参数吗?
@saua, it's just a question of whether it can be done out of interest really. I was hoping there'd be some neat way of altering the running bytecode, maybe using BCELor something. I've also followed up with this questionbecause I realised I wasn't totally sure when an enum should be used.
@saua,这只是一个是否真的可以出于兴趣而做的问题。我希望有一些改变正在运行的字节码的巧妙方法,也许使用BCEL或其他东西。我也跟进了这个问题,因为我意识到我不完全确定何时应该使用枚举。
I'm pretty convinced that the right answer would be to use a collection that ensured uniqueness instead of an enum if I want to be able to alter the contents safely at runtime.
如果我希望能够在运行时安全地更改内容,我非常确信正确的答案是使用确保唯一性的集合而不是枚举。
采纳答案by Tom Hawtin - tackline
No, enums are supposed to be a complete static enumeration.
不,枚举应该是一个完整的静态枚举。
At compile time, you might want to generate your enum .java file from another source file of some sort. You could even create a .class file like this.
在编译时,您可能希望从某种其他源文件生成 enum .java 文件。你甚至可以像这样创建一个 .class 文件。
In some cases you might want a set of standard values but allow extension. The usual way to do this is have an interface
for the interface and an enum
that implements that interface
for the standard values. Of course, you lose the ability to switch
when you only have a reference to the interface
.
在某些情况下,您可能需要一组标准值但允许扩展。执行此操作的常用方法是interface
为接口创建一个enum
,并interface
为标准值实现该接口。当然,switch
当您只有对interface
.
回答by Yuval
Behind the curtain, enums are POJOs with a private constructor and a bunch of public static final values of the enum's type (see herefor an example). In fact, up until Java5, it was considered best-practice to build your own enumeration this way, and Java5 introduced the enum
keyword as a shorthand. See the source for Enum<T>to learn more.
在幕后,枚举是具有私有构造函数和一组枚举类型的公共静态最终值的 POJO(参见此处的示例)。事实上,直到 Java5,以这种方式构建自己的枚举被认为是最佳实践,Java5 引入了enum
关键字作为速记。请参阅Enum<T>的来源以了解更多信息。
So it should be no problem to write your own 'TypeSafeEnum' with a public static final array of constants, that are read by the constructor or passed to it.
因此,使用由构造函数读取或传递给它的公共静态最终常量数组编写自己的“TypeSafeEnum”应该没有问题。
Also, do yourself a favor and override equals
, hashCode
and toString
, and if possible create a values
method
另外,帮自己一个忙并覆盖equals
, hashCode
and toString
,如果可能的话,创建一个values
方法
The question is how to use such a dynamic enumeration... you can't read the value "PI=3.14" from a file to create enum MathConstants
and then go ahead and use MathConstants.PI
wherever you want...
问题是如何使用这样的动态枚举......你不能从文件中读取值“PI = 3.14”来创建enum MathConstants
然后继续使用MathConstants.PI
你想要的任何地方......
回答by Peter Lawrey
You can load a Java class from source at runtime. (Using JCI, BeanShell or JavaCompiler)
您可以在运行时从源加载 Java 类。(使用 JCI、BeanShell 或 JavaCompiler)
This would allow you to change the Enum values as you wish.
这将允许您根据需要更改 Enum 值。
Note: this wouldn't change any classes which referred to these enums so this might not be very useful in reality.
注意:这不会改变任何引用这些枚举的类,因此这在现实中可能不是很有用。
回答by Eldelshell
You could try to assign properties to the ENUM you're trying to create and statically contruct it by using a loaded properties file. Big hack, but it works :)
您可以尝试将属性分配给您尝试创建的 ENUM,并使用加载的属性文件对其进行静态构造。大黑客,但它有效:)
回答by moffdub
I faced this problem on the formative project of my young career.
The approach I took was to save the values and the names of the enumeration externally, and the end goal was to be able to write code that looked as close to a language enum as possible.
我采用的方法是在外部保存枚举的值和名称,最终目标是能够编写看起来尽可能接近语言枚举的代码。
I wanted my solution to look like this:
我希望我的解决方案看起来像这样:
enum HatType
{
BASEBALL,
BRIMLESS,
INDIANA_JONES
}
HatType mine = HatType.BASEBALL;
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(HatType.BASEBALL));
And I ended up with something like this:
我最终得到了这样的结果:
// in a file somewhere:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
HatDynamicEnum hats = HatEnumRepository.retrieve();
HatEnumValue mine = hats.valueOf("BASEBALL");
// prints "BASEBALL"
System.out.println(mine.toString());
// prints true
System.out.println(mine.equals(hats.valueOf("BASEBALL"));
Since my requirements were that it had to be possible to add members to the enum at run-time, I also implemented that functionality:
由于我的要求是必须可以在运行时向枚举添加成员,因此我还实现了该功能:
hats.addEnum("BATTING_PRACTICE");
HatEnumRepository.storeEnum(hats);
hats = HatEnumRepository.retrieve();
HatEnumValue justArrived = hats.valueOf("BATTING_PRACTICE");
// file now reads:
// 1 --> BASEBALL
// 2 --> BRIMLESS
// 3 --> INDIANA_JONES
// 4 --> BATTING_PRACTICE
I dubbed it the Dynamic Enumeration "pattern", and you read about the original designand its revised edition.
我称它为动态计数“模式”,以及你阅读的原创设计和它的修订版。
The difference between the two is that the revised edition was designed after I really started to grok OO and DDD. The first one I designed when I was still writing nominally procedural DDD, under time pressure no less.
两者的区别在于,修订版是我真正开始理解OO和DDD之后设计的。当我还在写名义上的程序性 DDD 时,我设计的第一个,时间压力也不小。
回答by Andy
I needed to do something like this (for unit testing purposes), and I came across this - the EnumBuster: http://www.javaspecialists.eu/archive/Issue161.html
我需要做这样的事情(用于单元测试目的),我遇到了这个 - EnumBuster:http: //www.javaspecialists.eu/archive/Issue161.html
It allows enum values to be added, removed and restored.
它允许添加、删除和恢复枚举值。
Edit: I've only just started using this, and found that there's some slight changes needed for java 1.5, which I'm currently stuck with:
编辑:我刚刚开始使用它,发现 java 1.5 需要一些细微的更改,我目前坚持使用:
- Add array copyOf static helper methods (e.g. take these 1.6 versions: http://www.docjar.com/html/api/java/util/Arrays.java.html)
- Change EnumBuster.undoStack to a Stack
<Memento>
- In undo(), change undoStack.poll() to undoStack.isEmpty() ? null : undoStack.pop();
- The string VALUES_FIELD needs to be "ENUM$VALUES" for the java 1.5 enums I've tried so far
- 添加数组 copyOf 静态辅助方法(例如,采用这些 1.6 版本:http: //www.docjar.com/html/api/java/util/Arrays.java.html)
- 将 EnumBuster.undoStack 更改为堆栈
<Memento>
- 在 undo() 中,将 undoStack.poll() 更改为 undoStack.isEmpty() ?null : undoStack.pop();
- 到目前为止,我尝试过的 java 1.5 枚举的字符串 VALUES_FIELD 需要为“ENUM$VALUES”
回答by radfast
A working example in widespread use is in modded Minecraft. See EnumHelper.addEnum() methods on Github
一个广泛使用的工作示例是修改后的 Minecraft。请参阅Github上的 EnumHelper.addEnum() 方法
However, note that in rare situationspractical experience has shown that adding Enum members can lead to some issues with the JVM optimiser. The exact issues may vary with different JVMs. But broadly it seems the optimiser may assume that some internal fields of an Enum, specifically the size of the Enum's .values()
array, will not change. See issue discussion. The recommended solution there is not to make .values()
a hotspot for the optimiser. So if adding to an Enum's members at runtime, it should be done once and once only when the application is initialised, and then the result of .values()
should be cached to avoid making it a hotspot.
但是,请注意,在极少数情况下,实践经验表明,添加 Enum 成员可能会导致 JVM 优化器出现一些问题。确切的问题可能因不同的 JVM 而异。但从广义上讲,优化器可能会假设 Enum 的某些内部字段,特别是 Enum.values()
数组的大小,不会改变。请参阅问题讨论。推荐的解决方案不是.values()
为优化器设置热点。因此,如果在运行时添加到 Enum 的成员,则应仅在应用程序初始化时进行一次一次,然后.values()
应缓存结果以避免使其成为热点。
The way the optimiser works and the way it detects hotspots is obscure and may vary between different JVMs and different builds of the JVM. If you don't want to take the risk of this type of issue in production code, then don't change Enums at runtime.
优化器的工作方式及其检测热点的方式是模糊的,并且可能因不同的 JVM 和不同的 JVM 构建而异。如果您不想在生产代码中承担此类问题的风险,请不要在运行时更改 Enum。