2010-06-29 15 views
6

Dentro de mi código A tienen el siguiente superclase abstracta¿Usando un tipo genérico de una subclase dentro de su superclase abstracta?

public abstract class AbstractClass<Type extends A> {...} 

y algunas clases hijas como

public class ChildClassA extends AbstractClass<GenericTypeA> {...} 

public class ChildClassB extends AbstractClass<GenericTypeB> {...} 

Estoy buscando una manera elegante cómo puedo usar el tipo genérico de las clases hijas (GenericTypeA, GenericTypeB, ...) dentro de la clase abstracta de una manera genérica.

Para resolver este problema actualmente he definido el método

protected abstract Class<Type> getGenericTypeClass(); 

en mi clase abstracta e implementado el método

@Override 
protected Class<GenericType> getGenericTypeClass() { 
    return GenericType.class; 
} 

en cada clase de niños.

¿Es posible obtener el tipo genérico de las clases secundarias en mi clase abstracta sin implementar este método de ayuda?

BR,

Markus

Respuesta

10

Creo que es posible. Vi que esto se estaba usando en los patrones DAO junto con los genéricos. p.ej. Considere clases:

public class A {} 
public class B extends A {} 

Y su clase genérica:

import java.lang.reflect.ParameterizedType; 
    public abstract class Test<T extends A> { 

    private Class<T> theType; 

    public Test() { 
     theType = (Class<T>) (
       (ParameterizedType) getClass().getGenericSuperclass()) 
       .getActualTypeArguments()[0]; 
    } 

    // this method will always return the type that extends class "A" 
    public Class<T> getTheType() { 
     return theType; 
    } 

    public void printType() { 
     Class<T> clazz = getTheType(); 
     System.out.println(clazz); 
    } 
    } 

Puede tener una clase Prueba1 que se extiende de prueba con la clase B (que se extiende A)

public class Test1 extends Test<B> { 

    public static void main(String[] args) { 
     Test1 t = new Test1(); 

     Class<B> clazz = t.getTheType(); 

     System.out.println(clazz); // will print 'class B' 
     System.out.println(printType()); // will print 'class B' 
    } 
    } 
+0

No entiendo lo que hace realmente el código en el constructor de Test, pero funcionó. Ahora no tengo que usar los métodos de ayuda por más tiempo. Gracias :-) – Markus

+2

Utiliza la reflexión.Primero obtiene la superclase genérica (java.lang.reflect.Type) de la clase, en nuestro caso nunca será nula y sabemos que es un ParameterizedType, por lo que lo lanzamos y llamamos al método getActualTypeArguents que devuelve una matriz de los argumentos de tipo real, por ejemplo, B, del tipo. – naikus

+0

Ahhh, gracias por tu explicación. – Markus

0

no estoy seguro de entender completamente su pregunta - <Type> es el tipo genérico de la subclase, incluso cuando está siendo expresada en la clase abstracta. Por ejemplo, si su superclase abstracta define un método:

public void augment(Type entity) { 
    ... 
} 

y se ejemplariza un ChildClassA, sólo será capaz de llamar augment con una instancia de GenericTypeA.

Ahora, si quieres un literal de clase, deberás proporcionar el método que indicaste. Pero si solo quiere el parámetro genérico, no necesita hacer nada especial.

+0

Lo siento, Don Realmente entendiste tu punto. Tipo se extiende por los tipos genéricos de las clases secundarias. Por lo tanto, es posible devolver el tipo de subclase a Tipo y usarlo dentro de la superclase abstracta. – Markus

+0

@Markus - Ahora * Yo * no entiendo tu segunda oración, no creo que tenga sentido. No puedes lanzar un parámetro de tipo en ningún sentido; en la (s) definición (es) de clase, es simplemente un marcador de posición que apunta al tipo con el que realmente crea un objeto. Y las subclases no * extienden * tipo, proporcionan un límite concreto para ello. Entonces, cuando se invocan los métodos en 'AbstractClass' para una instancia de' ChildClassA', 'type' ** es **' GenericTypeA'. –

Cuestiones relacionadas