valueof usar recorrer que programacion estados enum como java enums

usar - que es un enum en java



¿Por qué el constructor de enum no puede acceder a los campos estáticos? (5)

¿Por qué el constructor de enum no puede acceder a campos y métodos estáticos? Esto es perfectamente válido con una clase, pero no está permitido con una enumeración.

Lo que trato de hacer es almacenar mis instancias enum en un Mapa estático. Considere este código de ejemplo que permite buscar por abreviatura:

public enum Day { Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat"); private final String abbreviation; private static final Map<String, Day> ABBREV_MAP = new HashMap<String, Day>(); private Day(String abbreviation) { this.abbreviation = abbreviation; ABBREV_MAP.put(abbreviation, this); // Not valid } public String getAbbreviation() { return abbreviation; } public static Day getByAbbreviation(String abbreviation) { return ABBREV_MAP.get(abbreviation); } }

Esto no funcionará ya que enum no permite referencias estáticas en su constructor. Sin embargo, funciona solo encuentra si se implementa como una clase:

public static final Day SUNDAY = new Day("Sunday", "Sun"); private Day(String name, String abbreviation) { this.name = name; this.abbreviation = abbreviation; ABBREV_MAP.put(abbreviation, this); // Valid }


Se llama al constructor antes de que se hayan inicializado todos los campos estáticos, porque los campos estáticos (incluidos los que representan los valores enum) se inicializan en orden textual, y los valores enum siempre aparecen antes que los otros campos. Tenga en cuenta que en su ejemplo de clase no ha mostrado dónde se inicializa ABBREV_MAP; si es después de DOMINGO, obtendrá una excepción cuando se inicialice la clase.

Sí, es un poco molesto y probablemente podría haberse diseñado mejor.

Sin embargo, la respuesta habitual en mi experiencia es tener un bloque static {} al final de todos los inicializadores estáticos, y hacer allí toda la inicialización estática, usando EnumSet.allOf para obtener todos los valores.


Cuando se carga una clase en la JVM, los campos estáticos se inicializan en el orden en que aparecen en el código. Por ej.

public class Test4 { private static final Test4 test4 = new Test4(); private static int j = 6; Test4() { System.out.println(j); } private static void test() { } public static void main(String[] args) { Test4.test(); } }

La salida será 0. Tenga en cuenta que la inicialización de test4 tiene lugar en el proceso de inicialización estática y durante este tiempo j aún no se ha inicializado como aparece más adelante. Ahora si cambiamos el orden de los inicializadores estáticos de modo que j llegue antes de test4. La salida será 6.Pero en el caso de los Enums no podemos alterar el orden de los campos estáticos. Lo primero en enum debe ser las constantes que son en realidad instancias finales estáticas de tipo enum. Así, para enums siempre se garantiza que los campos estáticos no se inicialicen antes de las constantes enum. Ya que no podemos dar ningún valor sensible a campos estáticos para usar enum constructor , no tendría sentido acceder a ellos en enum constructor.


tal vez esto es lo que quieres

public enum Day { Sunday("Sun"), Monday("Mon"), Tuesday("Tue"), Wednesday("Wed"), Thursday("Thu"), Friday("Fri"), Saturday("Sat"); private static final Map<String, Day> ELEMENTS; static { Map<String, Day> elements = new HashMap<String, Day>(); for (Day value : values()) { elements.put(value.element(), value); } ELEMENTS = Collections.unmodifiableMap(elements); } private final String abbr; Day(String abbr) { this.abbr = abbr; } public String element() { return this.abbr; } public static Day elementOf(String abbr) { return ELEMENTS.get(abbr); } }


El problema se resuelve a través de una clase anidada. Pros: es más corto y también mejor por el consumo de CPU. Contras: una clase más en la memoria JVM.

enum Day { private static final class Helper { static Map<String,Day> ABBR_TO_ENUM = new HashMap<>(); } Day(String abbr) { this.abbr = abbr; Helper.ABBR_TO_ENUM.put(abbr, this); } public static Day getByAbbreviation(String abbr) { return Helper.ABBR_TO_ENUM.get(abbr); }


Cita de JLS, sección "Declaraciones corporales de Enum" :

Sin esta regla, el código aparentemente razonable fallaría en el tiempo de ejecución debido a la circularidad de inicialización inherente a los tipos enum. (Existe una circularidad en cualquier clase con un campo estático "auto-tipado".) Aquí hay un ejemplo del tipo de código que fallaría:

enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); Color() { colorMap.put(toString(), this); } } Static initialization of this enum type would throw a NullPointerException because the static variable colorMap is

sin inicializar cuando se ejecutan los constructores para las constantes enum. La restricción anterior asegura que dicho código no compilará.

Tenga en cuenta que el ejemplo se puede refactorizar fácilmente para que funcione correctamente:

enum Color { RED, GREEN, BLUE; static final Map<String,Color> colorMap = new HashMap<String,Color>(); static { for (Color c : Color.values()) colorMap.put(c.toString(), c); } } The refactored version is clearly correct, as static initialization occurs top to bottom.