How is values() implemented for Java 6 enums?

JavaEnums

Java Problem Overview


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.

Java Solutions


Solution 1 - Java

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:

public enum Stuff {
   COW, POTATO, MOUSE;
}

You can actually look at the code that Java generates:

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 -d <output directory> -XD-printflat filename.java

Solution 2 - Java

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.

Solution 3 - Java

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

  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 of enum values.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionles2View Question on Stackoverflow
Solution 1 - JavalucasmoView Answer on Stackoverflow
Solution 2 - JavaJanuszView Answer on Stackoverflow
Solution 3 - JavaStephen CView Answer on Stackoverflow