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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1163076/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 15:27:00  来源:igfitidea点击:

How is values() implemented for Java 6 enums?

javaenums

提问by les2

In Java, you can create an enum as follows:

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

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)).

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

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

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.

它的代码是原生的吗?还是JVM/编译器有没有特殊对待,只有在不能证明不会被修改的情况下才从values()返回一个新的实例。

回答by lucasmo

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.

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

Given this simple enum:

鉴于这个简单的枚举:

public enum Stuff {
   COW, POTATO, MOUSE;
}

You can actually look at the code that Java generates:

你实际上可以看看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);
    }
}

You can look at how javac 'translates' your classes by making a temporary directory and running:

您可以通过创建一个临时目录并运行来查看 javac 如何“翻译”您的类:

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

回答by Janusz

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.

因此不存在性能问题,您不能意外更改枚举定义中的某些内容。

回答by Stephen C

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.

它的代码是原生的吗?还是JVM/编译器有没有特殊对待,只有在不能证明不会被修改的情况下才从values()返回一个新的实例。

1) No. Or at least not in current implementations. See @lucasmo's answer for the evidence.

1) 否。或者至少在当前的实现中不是。请参阅@lucasmo 的答案以获取证据。

2) AFAIK, no.

2)AFAIK,没有。

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.

假设它可以做到这一点。然而,证明数组从未在本地修改对于 JIT 执行来说是复杂且相对昂贵的。如果数组从调用的方法中“转义” values(),它会变得更复杂和更昂贵。

The chances are that this (hypothetical) optimization would not pay off ... when averaged over all Java code.

很可能这种(假设的)优化不会得到回报……当对所有 Java 代码进行平均时。

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 sense1says that it mustdo ... but it is not actually specified.

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

1 - It would be a gaping security hole if values()returned a shared (mutable) array of enumvalues.

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