2011-02-12 24 views
15

Mi objetivo es desarrollar una clase que pueda generar un objeto de una clase especificada.Cómo pasar una clase parametrizada como argumento

public class GetMe<T> { 
    public T get() { 
     Object obj = generateObject(); 
     return (T) obj; 
    } 
} 

Ahora, sé que esto no es posible debido a la eliminación. Entonces, podemos pasar una instancia de clase y usar eso para lanzar.

public class GetMe<T> { 
    public GetMe<T>(Class<T> clazz) { 
     this.clazz = clazz; 
    } 

    public T get() { 
     Object obj = generateObject(); 
     return clazz.cast(obj); 
    } 
} 

Esto funciona genial! Siempre que la clase no esté parametrizada. Si es así, entonces tengo un problema.

No tengo permiso para usar List<String>.class. Si paso en un ParameterizedType (que en sí mismo es difícil de generar), no hay un método cast para usar.

¿Hay alguna manera de salir de este atolladero?

+0

Hay una manera de retener genéricos en tiempo de ejecución, pero ¿qué es 'generateObject' y por qué no puede devolver un objeto de tipo' T'? – ide

+0

vea estos ejemplos, podría ayudar: http://serdom.eu/ser/2007/03/25/java-generics-instantiating-objects-of-type-parameter-without-using-class-literal –

+0

Digamos ' generateObject() 'es un deserializador de terceros. Sé que es de tipo T, porque lo serialé antes, pero el método solo devuelve Object. También podría ser el resultado de un método.invoque, que solo devuelve Object. –

Respuesta

2

El problema con List<String> es que, debido a su borrado, en el tiempo de ejecución no se distinguiría de ningún otro List<?>. La forma más sencilla de evitar esto es crear una nueva clase o interfaz que tiene la parte genérica "fijo", como

public interface StringList extends List<String> { 
    /* nothing to see here */ 
} 

De esta manera tiene una ficha tipo (el objeto StringList.class) que puede pasar alrededor en tiempo de ejecución y especifica exactamente lo que desea, pero sin la necesidad de genéricos en tiempo de ejecución.

+0

Me gusta esta idea, pero ¿no necesitaría muchas de estas clases "fijas"? ¿Hay alguna manera de hacer que funcionen? -tiempo? Usé la lista en mi ejemplo, en mi proyecto es en realidad 'Map >', donde Domain podría ser uno de ~ 200 objetos, algunos de los cuales están parametrizados. –

1

Aquí hay una pequeña idea. No estoy seguro si encajará en su contexto pero sin embargo:

public class GetMe<T> 
{ 
    public List<T> getList() { 
     @SuppressWarnings("unchecked") 
     List<T> result = (List<T>) new LinkedList(); 
     return result; 
    } 
} 

¡Salud!

+1

This es donde me inclino, solo para poder seguir con mi vida (aunque es "menos correcta"). –

5

Creo que super type tokens puede resolver este problema para usted.

+0

+1 porque los tokens de tipo súper son súper flexibles. Debería haberlos mencionado en mi respuesta. – Waldheinz

0

El primer problema es cómo piensa crear una instancia de un objeto List. Si revela más de lo que intenta construir, es posible que podamos ayudarlo mejor.

Es posible que desee utilizar Tipo en lugar de Clase. El tipo puede representar todos los tipos genéricos, aunque no es agradable trabajar con él.

abstract public class GetMe<T> 
{ 
    Type type; 
    public GetMe<T>(Type type) 
    { 
     this.type = type; 
    } 
} 

Otro problema es cómo crear un tipo genérico como List<String>. La "señal tipo estupendo" se ve bien en la sintaxis, en realidad es básicamente

static class XX extends TypeReference<List<String>>{} 
.... 
Type typeListString = Util.extract(XX.class); 

yo preferiría mucho de esta manera

List<String> f; 

Type typeListString = getDeclaredField("f").getGenericType(); 

En realidad, muchos de estos marcos que hacen tiempo de ejecución de fantasía magia genéricos están trabajando en campos de instancia solamente.

0

Creo que la confusión proviene del hecho de que estás tratando de crear un objeto a partir del List<>, que en realidad es una interfaz, no un objeto.
Así que no importa lo que se intenta, simplemente no puede crear una instancia de List<>, (interfaces no son clases reales, y no tiene constructores)

Trate de usar una restricción para evitar que las interfaces ponen en la declaración:

public class GetMe<T extends Object> 

Esto garantiza que T es una clase real y no una interfaz.

Cuestiones relacionadas