2011-08-30 8 views
11

Así que tengo mi enumeraciónJava public enum propósito método

public enum Sample { 
    ValueA{ 
     @Override 
    public String getValue(){ return "A"; } 
}, 
ValueB{ 
    @Override 
    public String getValue(){ return "B"; } 

    public void doSomething(){ } 
}; 
abstract public String getValue(); 
}; 

y tengo algún otro código de intentar usar la enumeración.

Sample.ValueB.doSomething(); 

¿Qué parece que debería ser válido, pero produce el error "El método doSomething() está definido para el tipo de muestra". A diferencia de

Sample value = Sample.ValueB; 
value.doSomething(); 

que produce el mismo error y parece razonable.

Supongo que hay una respuesta razonable sobre por qué la primera no funciona y se relaciona con los dos ejemplos que son equivalentes bajo el capó. Esperaba que alguien me indicara la documentación sobre por qué es así.

+0

Realmente ayudaría si dijera qué error está recibiendo ... –

+0

¿No debería llamar 'Sample.doSomething()'? – nfechner

+2

@ nfechner..el método 'doSomething()' no es estático .. –

Respuesta

15

El tipo del "campo" es ValueASample. Esto significa que solo puede invocar métodos en ValueA que proporciona Sample. De JLS §8.9.1. Enum Constants:

Los métodos de instancia declaradas en estos cuerpos de clase pueden ser invocados fuera del tipo envolvente enumeración sólo si se anulan los métodos accesibles del tipo envolvente enumeración.

que es más importante: Desde una perspectiva de diseño enum valores debe ser uniforme: si alguna operación es posible con un valor específico, entonces debería ser posible con todos los valores (aunque podría resultar en código diferente en ejecución).

10

Básicamente el tipo de tiempo de compilación de Sample.ValueB está todavía muestra, a pesar de que la -tiempo de ejecución tipo del valor será ValueB. Por lo tanto, sus dos fragmentos de código son equivalentes: los clientes no pueden ver los métodos "adicionales" que solo están presentes en algunos de sus valores enum.

Se puede pensar de manera efectiva de la enumeración como declarar un campo como este:

public static final Sample ValueB = new Sample() { 
    @Override 
    public String getValue(){ return "B"; } 

    public void doSomething(){ } 
}; 
4

Cuando se escribe

enum Sample 
{ 
    Value{ 
     public void doSomething() 
     { 
       //do something 
     } 
    }; 
} 

no está creando una instancia de la Sample enumeración, en lugar de una instancia de una subclase anónima de la enum Sample. Por eso, el método doSomething() no está definido.

Actualización: esto se puede demostrar de la siguiente manera:

probar este

System.out.println(Sample.ValueB.getClass().getName()); 

impresiones Sample$2

lo que significa que a pesar de tener el método doSomething() en el caso de Sample$2 que tienen llamado ValueB, lo está refiriendo a través de la referencia de superclase del tipo Sample y, por lo tanto, solo se usarán los métodos definidos en la clase Sample visible en tiempo de compilación.

Puede llamar a eso doSomething() en tiempo de ejecución mediante reflexión.

+1

Lo que es más importante: el tipo de "campo" 'Valor' ** seguirá siendo ** Muestra' y * no * 'Muestra $ 1'. –

3

public void doSomething(){ } tendrá el mismo efecto que private void doSomething(){ }.

doSomething() no está visible fuera de ValueB a menos que agregue doSomething() al Sample.

Cada valor Sample tiene el tipo Sample, por lo que no puede tener diferentes conjuntos de métodos para diferentes valores (desde la perspectiva exterior).

+0

Advertencia: los valores 'Sample' * * ** do ** tienen tipos más específicos si tienen un cuerpo de clase. Los campos 'Sample' * solo tienen el tipo' Sample'. –

+0

@Joachim: claro, pero esos tipos específicos son subclases anónimas de Muestra, por lo que "afuera" solo puede usar la interfaz definida por Muestra. No me despejé, lo siento. –