2012-02-01 13 views
16

Este código no se compilará porque hay una referencia ilegal a un campo estático.¿Por qué este código enum es una referencia ilegal a un campo estático?

public enum Foo { 

    A, 
    B; 

    private Foo[] foos = new Foo[] { Foo.A }; 

} 

¿No debería poder acceder a los campos estáticos de un inicializador de campo no estático? Por ejemplo:

public class Foo { 

    static int A; 

    private int[] foos = new int[] { Foo.A }; 

} 

Esto compila bien.

Nota, haciendo foos estático en el primer ejemplo de compilaciones.

Respuesta

16

conocer Java Language Specification, Tercera Edición, Sección 8.9 en http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.9

Es un error en tiempo de compilación para hacer referencia a un campo estático de un tipo de enumeración que no es una constante de tiempo de compilación (§ 15.28) de los constructores, bloques de inicializador de instancia, o inicializador de variable de instancia expresiones de ese tipo. Es un error en tiempo de compilación para los constructores de bloques de inicializador de instancia o variable de instancia expresiones de una constante enum e para referirse a sí mismo o al una constante enum del mismo tipo que se declara a la derecha de e.

Discusión

Sin esta regla, al parecer código razonable podría fallar en tiempo de ejecución debido a la circularidad de inicialización inherentes a los tipos de enumeración. (Existe una circularidad de ninguna clase con un campo estático "auto-escrito".) He aquí 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); 
     } 
    } 

inicialización estática de este tipo de enumeración arrojaría una NullPointerException porque la variable estática colorMap es sin inicializar cuando se ejecutan los constructores para las constantes enum. La restricción de anterior asegura que dicho código no se compilará.

7

Escrito a cabo de una manera más o menos equivalente, más simple, más cerca del código de bytes, vemos:

public final class Foo { 
    public static final Foo A = new Foo(); 
    public static final Foo B = new Foo(); 

    private Foo[] foos; 

    private Foo() { 
     this.foos = new Foo[] { Foo.A }; 
    } 
} 

se puede ver que para inicializar A estamos llamando al constructor, que dice A. Obviamente, mientras todavía está en el constructor A no se habrá inicializado.

(Como resultado, este código se compila más sencillo. Simplemente no hace lo que se podría esperar.)

es probable que desee Foo.values() en lugar de la variable foos ejemplo.

Cuestiones relacionadas