2011-07-06 927 views
7

Quiero escribir el código Java equivalente de un código C#.Java: crea un objeto cuyo tipo es un parámetro de tipo

Mi código C# es la siguiente:

public abstract class A<T> where T : A<T>, new() 
{ 
    public static void Process() 
    { 
     Process(new T()); 
    } 

    public static void Process(T t) 
    { 
     // Do Something... 
    } 
} 

public class B : A<B> 
{ 
} 

public class C : A<C> 
{ 
} 

equivalente Java de mi código es el siguiente.

public abstract class A<T extends A<T>> 
{ 
    public static <T extends A<T>> void process() 
    { 
     process(new T()); // Error: Cannot instantiate the type T 
    } 

    public static <T extends A<T>> void process(T t) 
    { 
     // Do Something... 
    } 

    public class B extends A<B> 
    { 
    } 

    public class C extends A<C> 
    { 
    } 
} 

Aquí el "nuevo()" sintaxis en las fuerzas de declaración de clases clases para escribir un constructer por defecto que hace posible llamar "nueva T()" de la clase base derivados. En otras palabras, cuando escribo la clase base, estoy seguro de que la clase derivada tendrá un constructer predeterminado, de modo que pueda instanciar un objeto de clase derivado de la clase base.

Mi problema en Java es que no puedo instanciar un objeto de clase derivado de superclase. Recibo el error "Cannot instantiate the type T" para llamar a "new T()". ¿Hay alguna forma similar a C# en Java o debería usar algo como patrón de prototipo y clonación?

Respuesta

5

Java no es compatible con reified generics, por lo que no hay equivalente a "new T();". La forma en que trabajo con esto es usar la reflexión contra un token de tipo. El token de tipo indica cuál es el tipo genérico.

public abstract class A<T> { 
    private Class<T> typeToken; 
    // constructor 
    public A() { 
     typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]; 
    } 
} 

A continuación, utilice la reflexión para crear una instancia de la clase. Es feo, pero hace el trabajo bien.

+0

Gracias por la respuesta rápida. Como intento crear una nueva instancia dentro de un método estático, no puedo hacer una llamada getClass(). Además, T.class no existe debido a la construcción en tiempo de compilación. Entonces, la reflexión no parece ser una solución para mí. O no lo pude encontrar aún (: –

+0

Esto solo funcionará si la subclase usa un parámetro de tipo concreto. Si la subclase fuera 'public class B extends A ' por ejemplo, esto tendría exactamente el mismo problema. Lo encuentro es mejor usar los tokens de tipo pero requerir que quien llama pase el token al constructor o método. –

0

Además, ten cuidado con esto si estás usando genéricos.

T[] someArray = new T[]; 

Esta es una razón para preferir ArrayList a las matrices. La razón del problema reside en la posibilidad de borrado y el borrado de tipos.

2

Puede encontrar alguna explicación de la diferencia entre los genéricos en C# y Java en this li nk - comparing java and C# generics.

Los genéricos de Java son una construcción completamente en tiempo de compilación. No puede hacer nada con los parámetros de tipo genérico que dependen de alguna manera de la información de tiempo de ejecución. Esto incluye:

  • creación de instancias de tipo genérico parámetros.
  • Creación de matrices de tipo genérico parámetros.
  • Consulta de la clase de tiempo de ejecución de un parámetro de tipo genérico .
  • Usando instanceof con los parámetros genéricos de tipo .

Puede omitir esta restricción con java.lang.reflect namepsace. Por ejemplo, vea esta pregunta sobre el stackoverflow: Genercs and Class.forName()

0

Solo use el estándar de pantano Abstract Factory pattern. A continuación, obtiene los beneficios adicionales que no está vinculando a un tipo específico, el tipo de implementación no necesita tener un constructor específico, la instancia puede tener alguna parametrización, las instancias se pueden almacenar en caché, etc., etc.

Por el amor de Dios, no use el reflejo.

0

Además de los otros comentarios, sugeriría no usar genéricos. No se necesitan, se eliminan en el momento de la compilación de todos modos, y si no los conoces bien, intentarás hacer que hagan cosas que no pueden.

vez que tenga su clase de funcionar correctamente, continuación añadir de vuelta al hotel. Su IDE, en ese momento, le dará una gran cantidad de consejos útiles e inteligible, y los genéricos le avisará cuando se utilizan objetos de la clase equivocada

Me parece posible que esta clase no necesite genéricos para nada cuando haya terminado. (No sé qué más puede hacer esta clase, y no entiendo el uso de los métodos estáticos; nunca tendrán acceso a la información de tipo de una instancia individual.)

0

En realidad, esto no es un problema en Java. El idioma está pasando la clase

public static <T extends A<T>> T process(Class<T> clazz) 
    { 
     T o = clazz.newInstance(); 
     process(o); 
     return o; 
    } 

    X x = process(X.class); // not too verbose 

añadí un valor de retorno para ilustrar el caso general.

Cuestiones relacionadas