2010-11-22 21 views
10

Tengo una clase genérica que representa un fragmento de texto. Ese fragmento de texto puede tener cualquiera de varios modos diferentes (diferentes tipos de resaltado). Esos modos están representados por un Enum. El Enum podría ser diferente para cada proyecto, pero debe implementar una interfaz que proporcione un método para combinar 2 de ellos (podría estar resaltado y en negrita). Así que tengo una interfaz:genéricos de Java de genéricos de

public interface TextFragmentMode<E extends Enum<E>> { 
    /** 
    * Will combine the supplied mode with the current mode and return the 
    * result. 
    * 
    * @param mode The mode to combine with. 
    * @return The combined mode. 
    */ 
    public E combine(E mode); 
} 

Entonces mi TextFragment es un recipiente tanto para una cadena de texto, y un modo. Pero cuando intento de declarar la clase:

public class TextFragment<E extends TextFragmentMode<E extends Enum<E>>> { 
    StringBuilder text; 
    E mode; 
    ... 

me sale el siguiente error:

Syntax error on token "extends", , expected

Que, de acuerdo con eclipsar el resaltado de sintaxis, se refería a la parte

E extends Enum<E> 

de el código. ¿Alguien sabe lo que estoy haciendo mal? Debo extrañar algo sobre Generics ...

--------------------- edit -------------- -----

fin estoy tomando el tiempo para leer Effective Java por Josh Bloch (segunda edición), y resulta que él va sobre este caso de uso como artículo 34: Emular enumeraciones extensibles con interfaces. Por mucho que me gustaría decir que la mente genial piense igual ... ¡Eso sería demasiado presumido!

+0

Thx que estaba luchando tan duro con P :) – Snicolas

Respuesta

12

TextFragment<E> tiene que decir dos cosas acerca de E.

  • Se "extiende" TextFragmentMode<E>. Para hacerlo, también debe restringirlo para ampliar Enum<E>.

Debido a Java wonkiness herencia, tiene que escribir que al revés:

public class TextFragment<E extends Enum<E> & TextFragmentMode<E>> { 
+0

Necesito probar esto ... Me pondré en contacto con usted ... – Lucas

+1

Sí, esto funciona. ¡Muchas gracias! Resulta que se llama Tipo de Intersección en la 3ª edición de JLS. Hubiera sido bueno si el tutorial de genéricos de Java incluso mencionara que podría haber escenarios de uso más avanzados. Para aquellos que encuentran esta pregunta, hay más información útil aquí: http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html y aquí: http://stackoverflow.com/questions/ 574529/coding-tip-intersection-types-and-java-enums Nuevamente, gracias. – Lucas

6

El problema es que usted está tratando de hacer E extender TextFragmentMode y Enum, que no son tipos relacionados. ¿Qué tipo E satisfaría ambas restricciones?

sospecho que desea dos parámetros de tipo, algo como esto:

public class TextFragment<E extends Enum<E>, M extends TextFragmentMode<E>> 

Ahora se han cada restricción expresada en un parámetro de tipo diferente, y ambos tienen sentido - sin duda se puede encontrar una E cuales es una enumeración, y un M que es un TextFragmentMode<E>. Sin embargo, es bastante complicado ...

... ¿usted definitivamente necesita que este sea genérico? ¿Qué vas a hacer con M en la clase? ¿No podría simplemente tomar un TextFragmentMode<E> como un parámetro de constructor (o lo que sea) y volverlo genérico en un parámetro de tipo nuevamente?

+0

Ok, por lo que su línea de resultados de código es una de las soluciones a las que llegué, pero todo es feo. Luego, cada vez que declaras/instancias necesitas ambos parámetros de tipo y ellos mismos son un poco largos. Terminas usando 80 caracteres en el nombre del tipo. Y en la práctica, mi tipo de aplicación fue: enumeración pública MyType implementa TextFragmentMode que es tanto una enumeración y una TextFragmentMode ... – Lucas

1

Usted necesidad de introducir un nuevo tipo que da cuenta de la cota de Enum

public class TextFragment<T extends Enum<T>, E extends TextFragmentMode<T>> { 
+0

Una vez más (por comentario anterior) No me gusta mucho este (aunque sería trabajar) a causa de la inelegancia Es muy desagradable de ver y parece que debería haber una mejor manera de hacerlo. – Lucas

-1

Sin pruebas, supongo:

public class TextFragment<E extends TextFragmentMode<E>> { 

Hmm, prueba corta muestra no parece para funcionar bien ...

+0

No compila, ya que necesita restringir 'E extiende Enum ', para que sea compatible con 'TextFragmentMode'. –