¿Cómo se implementa values ​​() para las enums de Java 6?

En Java, puede crear una enumeración de la siguiente manera:

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

Esta pregunta se refiere al método de “valores ()”. Específicamente, ¿cómo se implementa? Por lo general, podría saltar a la fuente para las clases de Java usando F3 o CTRL + clic en Eclipse (incluso para clases como Cadena, Carácter, Entero e incluso Enum). Es posible ver el origen de los otros métodos enum (por ejemplo, valueOf (String)).

¿”Values ​​()” crea una nueva matriz cada vez que se invoca? Si lo asigno a una variable local y luego modifico uno de los elementos, ¿qué ocurre? (Claramente esto no afectará el valor devuelto por los valores (), lo que implica que se asigna una nueva matriz cada vez).

¿El código es nativo? O el comstackdor / JVM lo trata especialmente, solo devuelve una nueva instancia de values ​​() cuando no puede probar que no se modificará.

Básicamente, el comstackdor (javac) traduce su enumeración a una matriz estática que contiene todos sus valores en tiempo de comstackción. Cuando llama a values ​​(), le da una copia .clone’d () de esta matriz.

Dada esta simple enumeración:

 public enum Stuff { COW, POTATO, MOUSE; } 

En realidad, puedes mirar el código que genera Java:

 public enum Stuff extends Enum { /*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); } } 

Puede ver cómo javac ‘traduce’ sus clases haciendo un directorio temporal y ejecutándose:

 javac -d  -XD-printflat filename.java 

Si lo asigna a una variable local, lo único que puede modificar es asignar otra enumeración a esta variable. Esto no cambiará la enumeración en sí porque solo está cambiando el objeto al que hace referencia su variable.

Parece que las enumeraciones son, de hecho, singleton, de modo que solo puede haber un elemento de cada enumeración en todo el progtwig, lo que hace que el operador == sea legal para las enumeraciones.

Entonces no hay ningún problema de rendimiento y no puedes cambiar accidentalmente algo en tu definición enum.

¿El código es nativo? O el comstackdor / JVM lo trata especialmente, solo devuelve una nueva instancia de values ​​() cuando no puede probar que no se modificará.

1) No. O al menos no en las implementaciones actuales. Ver la respuesta de @lucasmo para la evidencia.

2) AFAIK, no.

Hipotéticamente podría hacer esto. Sin embargo, demostrar que una matriz nunca se modifica localmente sería complicado y relativamente costoso para el JIT. Si la matriz “escapa” del método que llamó values() , se vuelve más compleja y más costosa.

Lo más probable es que esta optimización (hipotética) no valga la pena … cuando se promedia sobre todo el código Java.

El otro problema es que esta optimización (hipotética) podría abrir agujeros de seguridad.


Sin embargo, lo interesante es que el JLS no parece especificar que el miembro values() devuelve una copia de matriz. El sentido común 1 dice que debe hacer … pero en realidad no está especificado.

1 – Sería un gran agujero de seguridad si values() devolviera una matriz compartida (mutable) de valores enum .