Instanciando generics tipo en java

Duplicado: generics Java por qué esto no funcionará

Duplicar: instanciar una clase genérica en Java

Me gustaría crear un objeto de Generics Type en java. Por favor, sugiero cómo puedo lograr lo mismo.

Nota: Esto puede parecer un problema genérico trivial. Pero apuesto … no lo es. 🙂

supongamos que tengo la statement de clase como:

public class Abc { public T getInstanceOfT() { // I want to create an instance of T and return the same. } } 

 public class Abc { public T getInstanceOfT(Class aClass) { return aClass.newInstance(); } } 

Tendrá que agregar manejo de excepciones.

Debe pasar el tipo real en el tiempo de ejecución, ya que no forma parte del código de bytes después de la comstackción, por lo que no hay forma de conocerlo sin proporcionarlo explícitamente.

En el código que publicaste, es imposible crear una instancia de T ya que no sabes qué tipo es:

 public class Abc { public T getInstanceOfT() { // There is no way to create an instance of T here // since we don't know its type } } 

Por supuesto, es posible si tiene una referencia a Class y T tiene un constructor predeterminado, simplemente llame a newInstance() en el objeto Class .

Si subclase Abc , puede incluso solucionar el problema del borrado de tipos y no tendrá que pasar ninguna referencia de Class torno a:

 import java.lang.reflect.ParameterizedType; public class Abc { T getInstanceOfT() { ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); Class type = (Class) superClass.getActualTypeArguments()[0]; try { return type.newInstance(); } catch (Exception e) { // Oops, no default constructor throw new RuntimeException(e); } } public static void main(String[] args) { String instance = new SubClass().getInstanceOfT(); System.out.println(instance.getClass()); } } class SubClass extends Abc { } 

Lo que usted escribió no tiene ningún sentido, los generics en Java están destinados a agregar la funcionalidad del polymorphism paramétrico a los objetos.

Qué significa eso? Significa que desea mantener algunas variables de tipo de sus clases indecisas, para poder usar sus clases con muchos tipos diferentes.

Pero su variable de tipo T es un atributo que se resuelve en tiempo de ejecución, el comstackdor de Java comstackrá su clase demostrando seguridad de tipo sin intentar saber qué tipo de objeto es T por lo que es imposible que use una variable de tipo en un método estático El tipo está asociado a una instancia en tiempo de ejecución del objeto, mientras que public void static main(..) está asociada a la definición de la clase y en ese scope T no significa nada.

Si desea utilizar una variable de tipo dentro de un método estático, debe declarar el método como genérico (esto porque, como las variables de tipo explicado de una clase de plantilla están relacionadas con su instancia en tiempo de ejecución ), no la clase:

 class SandBox { public static  void myMethod() { T foobar; } } 

esto funciona, pero, por supuesto, no con el método main , ya que no hay forma de llamarlo de forma genérica.

EDITAR : El problema es que debido a la borradura de tipo solo se comstack una clase genérica y se pasa a JVM. El verificador de tipos simplemente verifica si el código es seguro, y luego, como demostró, se descarta todo tipo de información genérica .

Para instanciar T , necesita saber el tipo de T , pero puede tratarse de muchos tipos al mismo tiempo, por lo que una solución requiere solo la cantidad mínima de reflexión para usar Class para crear instancias de objetos nuevos:

 public class SandBox { Class reference; SandBox(Class classRef) { reference = classRef; } public T getNewInstance() { try { return reference.newInstance(); } catch (Exception e) { e.printStackTrace(); } return null; } public static void main(String[] args) { SandBox t = new SandBox(String.class); System.out.println(t.getNewInstance().getClass().getName()); } } 

Por supuesto, esto implica que el tipo que desea instanciar:

  • no es un tipo primitivo
  • tiene un constructor por defecto

Para operar con diferentes tipos de constructores, debes profundizar en la reflexión.

Necesita obtener la información de tipo estáticamente. Prueba esto:

 public class Abc { private Class clazz; public Abc(Class clazz) { this.clazz = clazz; } public T getInstanceOfT() throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } 

Úselo como tal:

  Abc abc = new Abc(String.class); abc.getInstanceOfT(); 

Dependiendo de sus necesidades, es posible que desee utilizar Class Class lugar.

La única forma de hacerlo funcionar es usar Geneticos Reificados . Y esto no es compatible con Java (aún? Fue planeado para Java 7, pero se ha pospuesto). En C #, por ejemplo, se admite suponiendo que T tiene un constructor predeterminado . Incluso puede obtener el tipo de tiempo de ejecución por typeof(T) y obtener los constructores por Type.GetConstructor() . No hago C #, por lo que la syntax puede no ser válida, pero se ve más o menos así:

 public class Foo where T:new() { public void foo() { T t = new T(); } } 

La mejor “solución alternativa” para esto en Java es pasar un argumento de Class como método en su lugar, ya que varias respuestas ya se señalaron.

En primer lugar, no puede acceder al parámetro de tipo T en el método principal estático, solo en miembros de clase no estáticos (en este caso).

En segundo lugar, no puede instanciar T porque Java implementa generics con Type Erasure . Casi toda la información genérica se borra en el momento de la comstackción.

Básicamente, no puedes hacer esto:

 T member = new T(); 

Aquí hay un buen tutorial sobre generics .

Parece que no entiendes cómo funcionan los generics. Es posible que desee consultar http://java.sun.com/j2se/1.5.0/docs/guide/language/generics.html Básicamente, lo que podría hacer es algo así como

 public class Abc { T someGenericThing; public Abc(){} public T getSomeGenericThing() { return someGenericThing; } public static void main(String[] args) { // create an instance of "Abc of String" Abc stringAbc = new Abc(); String test = stringAbc.getSomeGenericThing(); } } 

Estaba implementando lo mismo usando el siguiente enfoque.

 public class Abc { T myvar; public T getInstance(Class clazz) throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } 

Estaba tratando de encontrar una mejor manera de lograr lo mismo.

¿No es posible?

Escriba solución de borrado

Inspirado por la respuesta de @martins , escribí una clase de ayuda que me permite resolver el problema del borrado de tipos. Usando esta clase (y un pequeño truco feo) puedo crear una nueva instancia de un tipo de plantilla:

 public abstract class C_TestClass { T createTemplateInstance() { return C_GenericsHelper.createTemplateInstance( this, 0 ); } public static void main( String[] args ) { ArrayList list = new C_TestClass >(){}.createTemplateInstance(); } } 

El truco feo aquí es hacer que la clase sea abstract modo que el usuario de la clase se ve obligado a subtitularla. Aquí estoy subclasificando al agregar {} después de la llamada al constructor. Esto define una nueva clase anónima y crea una instancia de la misma.

Una vez que la clase genérica se subtipo con tipos concretos de plantilla, puedo recuperar los tipos de plantilla.


 public class C_GenericsHelper { /** * @param object instance of a class that is a subclass of a generic class * @param index index of the generic type that should be instantiated * @return new instance of T (created by calling the default constructor) * @throws RuntimeException if T has no accessible default constructor */ @SuppressWarnings( "unchecked" ) public static  T createTemplateInstance( Object object, int index ) { ParameterizedType superClass = (ParameterizedType )object.getClass().getGenericSuperclass(); Type type = superClass.getActualTypeArguments()[ index ]; Class instanceType; if( type instanceof ParameterizedType ) { instanceType = (Class )( (ParameterizedType )type ).getRawType(); } else { instanceType = (Class )type; } try { return instanceType.newInstance(); } catch( Exception e ) { throw new RuntimeException( e ); } } } 

Parece que está intentando crear la clase que sirve como punto de entrada a su aplicación como genérico, y eso no funcionará … La JVM no sabrá qué tipo se supone que debe usar cuando se lo instancia como empiezas la aplicación

Sin embargo, si este fuera el caso más general, entonces algo así sería lo que estás buscando:

 public MyGeneric getMeAGenericObject(){ return new MyGeneric(); } 

o quizás:

 MyGeneric objMyObject = new MyGeneric(); 

Hay formas estrafalarias alrededor de esto cuando realmente tienes que hacerlo.

Aquí hay un ejemplo de un método de transformación que me parece muy útil; y proporciona una forma de determinar la clase concreta de un genérico.

Este método acepta una colección de objetos como entrada, y devuelve una matriz donde cada elemento es el resultado de llamar a un campo getter en cada objeto en la colección de entrada. Por ejemplo, supongamos que tiene una List y quiere una String[] contenga el apellido de todos.

El tipo de valor de campo devuelto por el getter es especificado por el E genérico, y necesito crear una instancia de un array de tipo E[] para almacenar el valor de retorno.

El método en sí es un poco feo, pero el código que escribe que lo usa puede ser mucho más limpio.

Tenga en cuenta que esta técnica solo funciona cuando en algún lugar de los argumentos de entrada hay un objeto cuyo tipo coincide con el tipo de retorno, y puede determinarlo de manera determinista. Si las clases concretas de sus parámetros de entrada (o sus subobjetos) no pueden decirle nada sobre los generics, entonces esta técnica no funcionará.

 public  E[] array (Collection c) { if (c == null) return null; if (c.isEmpty()) return (E[]) EMPTY_OBJECT_ARRAY; final List collect = (List) CollectionUtils.collect(c, this); final Class elementType = (Class) ReflectionUtil.getterType(c.iterator().next(), field); return collect.toArray((E[]) Array.newInstance(elementType, collect.size())); } 

El código completo está aquí: https://github.com/cobbzilla/cobbzilla-utils/blob/master/src/main/java/org/cobbzilla/util/collection/FieldTransformer.java#L28

 Abc abcInstance = new Abc (); 

..por ejemplo