Java 6枚举如何实现values()?

在Java中,您可以创build一个枚举,如下所示:

public enum Letter { A, B, C, D, E, F, G; static { for(Letter letter : values()) { // do something with letter } } } 

这个问题涉及“values()”方法。 具体来说,它是如何实施的? 通常,我可以使用F3或CTRL +在Eclipse中跳转到Java类的源代码(甚至对于像String,Character,Integer,甚至Enum类)。 可以查看其他枚举方法的来源(例如,valueOf(String))。

“values()”每次调用时都会创build一个新的数组? 如果我将它分配给一个局部variables,然后修改其中一个元素,会发生什么(显然这不会影响values()返回的值,这意味着每次都分配一个新的数组)。

它的代码是原生的吗? 或者JVM /编译器专门处理它,只有当它不能certificate它不会被修改时才从values()返回一个新的实例。

基本上,编译器(javac)将您的枚举转换为静态数组,在编译时包含所有的值。 当你调用values()时,它会给你一个.clone'd()这个数组的副本。

鉴于这个简单的枚举:

 public enum Stuff { COW, POTATO, MOUSE; } 

你可以看看Java生成的代码:

 public enum Stuff extends Enum<Stuff> { /*public static final*/ COW /* = new Stuff("COW", 0) */, /*public static final*/ POTATO /* = new Stuff("POTATO", 1) */, /*public static final*/ MOUSE /* = new Stuff("MOUSE", 2) */; /*synthetic*/ private static final Stuff[] $VALUES = new Stuff[]{Stuff.COW, Stuff.POTATO, Stuff.MOUSE}; public static Stuff[] values() { return (Stuff[])$VALUES.clone(); } public static Stuff valueOf(String name) { return (Stuff)Enum.valueOf(Stuff.class, name); } private Stuff(/*synthetic*/ String $enum$name, /*synthetic*/ int $enum$ordinal) { super($enum$name, $enum$ordinal); } } 

你可以看看javac是如何通过build立一个临时目录并运行:

 javac -d <output directory> -XD-printflat filename.java 

如果将其分配给本地variables,则唯一可以修改的是将另一个枚举分配给此variables。 这不会改变枚举本身,因为你只是改变对象的variables引用。

看来,枚举实际上是单身,所以每个枚举中只有一个元素可以存在于整个程序中,这使得==运算符对于枚举是合法的。

所以没有性能问题,你不能无意中改变你的枚举定义的东西。

它的代码是原生的吗? 或者JVM /编译器专门处理它,只有当它不能certificate它不会被修改时才从values()返回一个新的实例。

1)否,或者至less不是在当前的实现。 请参阅@卢卡斯莫的证据答案。

2)AFAIK,没有。

假设它可以做到这一点。 但是,certificate一个数组从未被本地修改过,对于JIT来说是比较复杂和相对昂贵的。 如果该数组从名为values()的方法中“转义”,则它变得更复杂且更昂贵。

当所有的Java代码平均时,这个(假设的)优化是不会有好结果的。

另一个问题是这个(假设的)优化可能会打开安全漏洞。


有趣的是,JLS似乎没有指定values()成员返回一个数组副本。 常识1说,它必须做…但实际上没有指定。

1 – 如果values()返回一个enum值的共享(可变)数组,这将是一个巨大的安全漏洞。