Java 6 枚举的 value() 是如何实现的?
在 Java 中,您可以按如下方式创建枚举:
public enum Letter {
A, B, C, D, E, F, G;
static {
for(Letter letter : values()) {
// do something with letter
}
}
}
这个问题涉及“values()”方法。 具体来说,是如何实施的呢? 通常,我可以在 Eclipse 中使用 F3 或 CTRL+Click 跳转到 Java 类的源代码(甚至对于 String、Character、Integer 甚至 Enum 等类)。 可以查看其他枚举方法的源代码(例如,valueOf(String))。
“values()”每次调用时都会创建一个新数组吗? 如果我将它分配给一个局部变量,然后修改其中一个元素,会发生什么(显然这不会影响 value() 返回的值,这意味着每次都会分配一个新数组)。
它的代码是原生的吗? 或者JVM/编译器是否对其进行了特殊处理,只有在无法证明不会被修改时才从values()返回一个新实例。
In Java, you can create an enum as follows:
public enum Letter {
A, B, C, D, E, F, G;
static {
for(Letter letter : values()) {
// do something with letter
}
}
}
This question concerns the "values()" method. Specifically, how is it implemented? Usually, I could jump to the source for Java classes using F3 or CTRL+Click in Eclipse (even for classes like String, Character, Integer, and even Enum). It is possible to view the source of the other enum methods (e.g., valueOf(String)).
Does "values()" create a new array each time it is invoked? If I assign it to a local variable and then modify one of the elements, what happens (clearly this won't affect the value returned by values(), which implies that a new array is allocated each time).
Is the code for it native? Or does the JVM / compiler treat it specially, only returning a new instance from values() when it cannot prove that it will not be modified.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
基本上,编译器 (javac) 在编译时将枚举转换为包含所有值的静态数组。 当您调用values()时,它会为您提供该数组的.clone'd()副本。
给定这个简单的枚举:
您实际上可以查看 Java 生成的代码:
您可以通过创建临时目录并运行来查看 javac 如何“翻译”您的类:
Basically, the compiler (javac) translates your enum into a static array containing all of your values at compile time. When you call values(), it gives you a .clone'd() copy of this array.
Given this simple enum:
You can actually look at the code that Java generates:
You can look at how javac 'translates' your classes by making a temporary directory and running:
如果将其分配给局部变量,则唯一可以修改的就是将另一个枚举分配给该变量。 这不会更改枚举本身,因为您只是更改变量引用的对象。
看来枚举实际上是单例,因此每个枚举中只能存在一个元素,这使得 == 运算符对于枚举来说是合法的。
因此不存在性能问题,并且您不会意外更改枚举定义中的某些内容。
If you assign it to a local variable the only thing that you can modify is assigning another enum to this variable. This will not change the enum itself because you are only changing the object your variable references.
It seems that the enums are in fact singletons so that only one element from each enum can exist in you whole program this makes the == operator legal for enums.
So there is no performance problem and you can't accidentally change something in your enum definition.
1) 不。或者至少在当前的实现中不是。 请参阅@lucasmo 的回答以获取证据。
2)据我所知,不。
假设它可以做到这一点。 然而,证明数组从未在本地被修改对于 JIT 的执行来说将是复杂且相对昂贵的。 如果数组从调用
values()
的方法中“逃逸”,它会变得更加复杂。 更贵。当对所有 Java 代码进行平均时,这种(假设的)优化很可能不会带来回报。
另一个问题是这种(假设的)优化可能会带来安全漏洞。
但有趣的是,JLS 似乎没有指定
values()
成员返回数组副本。 常识1说它必须这样做......但实际上并没有指定。1 - 如果
values()
返回一个共享(可变)enum
值数组,这将是一个巨大的安全漏洞。1) No. Or at least not in current implementations. See @lucasmo's answer for the evidence.
2) AFAIK, no.
Hypothetically it could do this. However, proving that an array is never modified locally would be complicated and relatively expensive for the JIT to perform. If the array "escapes" from the method that called
values()
, it gets more complex & more expensive.The chances are that this (hypothetical) optimization would not pay off ... when averaged over all Java code.
The other issue is that this (hypothetical) optimization might open up security holes.
The interesting thing though is that the JLS does not seem to specify that the
values()
member returns an array copy. Common sense1 says that it must do ... but it is not actually specified.1 - It would be a gaping security hole if
values()
returned a shared (mutable) array ofenum
values.