2011-01-11 19 views
5

¿Puede alguien explicar el uso de plantillas genéricas recursivas más complejas a continuación?Plantilla genérica recursiva de Java: ¿qué significa esto ... S extends Writer <E>> extends Entidad <E,S>

public abstract class Data<E extends Data<E, S>, 
          S extends Writer<E>> extends Entity<E,S> 

¿Qué debemos tener en cuenta durante el uso de los genéricos recursivas, como la de arriba. ¿Y cómo será la relación y las reglas entre estos tipos, aquí E & S?

Si corresponde, proporcione algunos recursos/enlaces/libros sobre este tipo de uso genérico. Sé un libro hablando de esto, Effective Java, 2ª ed por Joshua Bloch (artículo 27)

+0

Si fuera un jefe que descartar el que escribió el código. Qué demonios es eso ? Uno debe entender algo a primera vista –

Respuesta

2

Data tiene dos parámetros, E que en última instancia debe ser una instancia de sí mismo, y S que debe ser capaz de Writer una instancia de sí mismo (más específicamente, el mismo tipo de instancia de sí mismo especificado por E). Finalmente, Data<E,S> también califica como/hereda capacidades de Entity parametrizadas por el mismo E y S (es decir, Entity es de Data<E,S> y Writer<E>).

Una aplicación concreta podría ser algo como

NumericalData extends Data<NumericalData, NumWriter> donde NumWriter implementos/extiende Writer<NumericalData> y NumericalData también califica como un Entity<NumericalData, NumWriter>.

EDITAR:

¿Por qué hacer algo como esto? Uno podría querer definir métodos genéricos en la clase abstracta que se basan en un argumento/retorno que cumpla con los criterios Data<E,S>, pero también quiera poder regresar/trabajar con el tipo más explícito. Por ejemplo, en Data<E,S>, puede haber

E doSomething(E toThis) { toThis.aDataClassMethod(); return toThis; } 

La clase puede hacer la primera llamada, porque sabe E es una Data<E,S>, y devolver el tipo más específico porque sabe toThis es un E.

Para ser honesto, los genéricos recursivos son típicamente el camino demasiado inteligente. Pueden ser útiles, pero muchas veces son simplemente "pulcros" y uno trata de resolver el problema en torno a algo inteligente en lugar de viceversa.

3

Comencemos con el más fácil

S extends Writer<E> 

Cualquier clase de tipo S debe ser un escritor de la clase E

extends Entity<E,S> 

Justo aquí la herencia, la clase de datos se extiende a la clase de entidad.

E extends Data<E, S> 

Cualquier clase utilizada para E misma debe heredar de la clase de datos y hereda/implementa los métodos genéricos de datos utilizando su propio tipo y un escritor compatible con sí mismo.

La relación entre E & S debe ser algo como lo siguiente:

//E = Example, S = ExampleWriter 
public class ExampleWriter implements Writer<Example>{ 
//... 
} 
public class Example extends Data<Example,ExampleWriter>{ 
//... 
} 

a tener en cuenta: con los genéricos proporcionando una Writer<SomeChildOfExample> o una fuerza Writer<SomeParentOfExample> o podrían no crear errores de compilación, esto depende de la genérica métodos definidos en ambos tipos genéricos.

+0

El ejemplo que ha especificado para describir la relación se ve bien. – manikanta

0

Estoy de acuerdo con Carl en que los tipos recursivos tienden a ser "inteligentes" a expensas de la usabilidad. Sin embargo, hay MUCHOS casos en que Java rtl debería haber empleado este idioma para imponer la seguridad de tipo estricto y para evitar el barril de monos que tenemos como biblioteca de clases.

Por ejemplo, incluso objeto probablemente debería ser un tipo recursivo abstracto, al menos, para hacer cumplir las estrictas normas de la igualdad:

public abstract class Object<T extends Object<T>> { 
    ... 
    public boolean equals(o :T) { 
    ... 
    } 
} 

cheques No más instanceof en sus iguales() implementaciones y, más importante, mejor tiempo de compilación para llamadas equals().

Dicho esto, tal vez una de las características más adecuado y menos complicada sería un tipo de "Ser" ...

Cuestiones relacionadas