xmlns template sirve setactioncommand que para implementar bootstrap java generics enums switch-statement

template - setactioncommand java para que sirve



Usando Java Generics con Enums (5)

Actualización: gracias a todos los que ayudaron: la respuesta a esta pregunta fue lo que no noté en mi código más complejo y lo que no sabía sobre los tipos de devolución covariante de Java5.

Mensaje original:

He estado jugando con algo esta mañana. Aunque sé que podría abordar todo este problema de manera diferente, me estoy obsesionando en descubrir por qué no está funcionando de la manera que esperaba. Después de dedicar un tiempo a leer esto, descubro que no estoy más cerca de comprender, así que lo ofrezco como una pregunta para ver si simplemente estoy siendo estúpido o si realmente hay algo que no entiendo que esté sucediendo aquí .

He creado una jerarquía de eventos personalizada como:

public abstract class AbstractEvent<S, T extends Enum<T>> { private S src; private T id; public AbstractEvent(S src, T id) { this.src = src; this.id = id; } public S getSource() { return src; } public T getId() { return id; } }

Con una implementación concreta como tal:

public class MyEvent extends AbstractEvent<String, MyEvent.Type> { public enum Type { SELECTED, SELECTION_CLEARED }; public MyEvent(String src, Type t) { super(src, t); } }

Y luego creo un evento así:

fireEvent(new MyEvent("MyClass.myMethod", MyEvent.Type.SELECTED));

Donde mi fireEvent se define como:

protected void fireEvent(MyEvent event) { for(EventListener l : getListeners()) { switch(event.getId()) { case SELECTED: l.selected(event); break; case SELECTION_CLEARED: l.unselect(event); break; } } }

Así que pensé que esto sería bastante sencillo, pero resulta que la llamada a event.getId () hace que el compilador me diga que no puedo activar Enums, solo valores int convertibles o constantes de enumeración.

Es posible agregar el siguiente método a MyEvent:

public Type getId() { return super.getId(); }

Una vez que hago esto, todo funciona exactamente como lo esperaba. No solo estoy interesado en encontrar una solución alternativa para esto (porque obviamente tengo una), estoy interesado en cualquier idea que la gente pueda tener sobre POR QUÉ esto no funciona como lo esperaba.


Acabo de intentar esto (copie y pegó su código) y no puedo duplicar un error del compilador.

public abstract class AbstractEvent<S, T extends Enum<T>> { private S src; private T id; public AbstractEvent(S src, T id) { this.src = src; this.id = id; } public S getSource() { return src; } public T getId() { return id; } }

y

public class MyEvent extends AbstractEvent<String, MyEvent.Type> { public enum Type { SELECTED, SELECTION_CLEARED }; public MyEvent( String src, Type t ) { super( src, t ); } }

y

public class TestMain { protected void fireEvent( MyEvent event ) { switch ( event.getId() ) { case SELECTED: break; case SELECTION_CLEARED: break; } } }


En muy poco tiempo, porque T se borra a una clase Enum, no a una constante Enum, por lo que parece que la instrucción compilada está activando el resultado de que getID sea Enum, como en esta firma:

Enum getId();

Cuando lo reemplaza con un tipo específico, entonces está cambiando el valor de retorno y puede activarlo.

EDITAR: La resistencia me dio curiosidad, así que hice un código:

public enum Num { ONE, TWO } public abstract class Abstract<T extends Enum<T>> { public abstract T getId(); } public abstract class Real extends Abstract<Num> { } public static void main(String[] args) throws Exception { Method m = Real.class.getMethod("getId"); System.out.println(m.getReturnType().getName()); }

El resultado es java.lang.Enum, no Num. T se borra a Enum en el momento de la compilación, por lo que no puede activarlo.

EDITAR:

Probé las muestras de código con las que todos están trabajando, y también funcionan para mí, así que aunque sospecho que esto subyace en el código real más complejo, la muestra que se publica en realidad compila y funciona bien.


Esto no está relacionado con los genéricos. La declaración de cambio para enum en java solo puede usar los valores de esa enumeración en particular, por lo tanto, está prohibido especificar el nombre de enumeración. Esto debería funcionar:

switch(event.getId()) { case SELECTED: l.selected(event); break; case SELECTION_CLEARED: l.unselect(event); break; }

Actualización : Ok, aquí hay un código real (que tuve que cambiar un poco para compilarlo sin dependencias) que he copiado / pegado, compilado y ejecutado, sin errores:

AbstractEvent.java

public abstract class AbstractEvent<S, T extends Enum<T>> { private S src; private T id; public AbstractEvent(S src, T id) { this.src = src; this.id = id; } public S getSource() { return src; } public T getId() { return id; } }

MyEvent.java

public class MyEvent extends AbstractEvent<String, MyEvent.Type> { public enum Type { SELECTED, SELECTION_CLEARED }; public MyEvent(String src, Type t) { super(src, t); } }

Prueba.java

public class Test { public static void main(String[] args) { fireEvent(new MyEvent("MyClass.myMethod", MyEvent.Type.SELECTED)); } private static void fireEvent(MyEvent event) { switch(event.getId()) { case SELECTED: System.out.println("SELECTED"); break; case SELECTION_CLEARED: System.out.println("UNSELECTED"); break; } } }

Esto compila y corre bajo Java 1.5 muy bien. ¿Que me estoy perdiendo aqui?


Yishai tiene razón, y la frase mágica es " tipos de retorno covariante ", que es nuevo en Java 5.0; no puede activar Enum, pero puede activar su clase Type que amplíe Enum. Los métodos en AbstractEvent que son heredados por MyEvent están sujetos a borrado de tipo. Al anularlo, está redirigiendo el resultado de getId() hacia su clase Type de una manera que Java puede manejar en tiempo de ejecución.


Funciona para mi.

Completo programa de prueba de cortar y pegar:

enum MyEnum { A, B } class Abstract<E extends Enum<E>> { private final E e; public Abstract(E e) { this.e = e; } public E get() { return e; } } class Derived extends Abstract<MyEnum> { public Derived() { super(MyEnum.A); } public static int sw(Derived derived) { switch (derived.get()) { case A: return 1; default: return 342; } } }

¿Estás usando algún compilador peculiar?