tutorial objeto instanciar genericos generico genericas generica generic crear comparar como clases arreglos arquitectura java generics

objeto - instanciar clases genericas java



Crear una clase genérica en Java (9)

Sé que los genéricos de Java son algo inferiores a los de .Net.

Tengo una clase genérica Foo<T> , y realmente necesito crear una instancia de T en Foo usando un constructor sin parámetros. ¿Cómo se puede solucionar la limitación de Java?


Realmente necesito crear una instancia de T en Foo usando un constructor sin parámetros

La respuesta simple es "no se puede hacer eso" java usa borrado de tipo para implementar genéricos que le impediría hacer esto.

¿Cómo se puede solucionar la limitación de Java?

Una forma (podría haber otras) es pasar el objeto que pasaría la instancia de T al constructor de Foo<T> . O puede tener un método setBar(T theInstanceofT); para obtener su T en lugar de instanciar en la clase en sí mismo.


Aquí hay una forma bastante artificial para hacerlo sin usar explícitamente un argumento de constructor. Necesita extender una clase abstracta parametrizada.

public class Test { public static void main(String [] args) throws Exception { Generic g = new Generic(); g.initParameter(); } } import java.lang.reflect.ParameterizedType; public abstract class GenericAbstract<T extends Foo> { protected T parameter; @SuppressWarnings("unchecked") void initParameter() throws Exception, ClassNotFoundException, InstantiationException { // Get the class name of this instance''s type. ParameterizedType pt = (ParameterizedType) getClass().getGenericSuperclass(); // You may need this split or not, use logging to check String parameterClassName = pt.getActualTypeArguments()[0].toString().split("//s")[1]; // Instantiate the Parameter and initialize it. parameter = (T) Class.forName(parameterClassName).newInstance(); } } public class Generic extends GenericAbstract<Foo> { } public class Foo { public Foo() { System.out.println("Foo constructor..."); } }


Desde https://.com/a/2434094/848072 . Necesitas un constructor por defecto para la clase T.

import java.lang.reflect.ParameterizedType; class Foo { public bar() { ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass(); Class type = (Class) superClass.getActualTypeArguments()[0]; try { T t = type.newInstance(); //Do whatever with t } catch (Exception e) { // Oops, no default constructor throw new RuntimeException(e); } } }


Los genéricos en Java son generalmente más poderosos que en C #.

Si quiere construir un objeto pero sin cablear un constructor / método estático, use una fábrica abstracta. Debería poder encontrar información detallada y tutoriales sobre Abstract Factory Pattern en cualquier libro de patrones de diseño básico, introducción a OOP o en todo el interwebs. No vale la pena duplicar código aquí, aparte de mencionar que la sintaxis de cierre de Java apesta.

IIRC, C # tiene un caso especial para especificar que un tipo genérico tiene un constructor sin args. Esta irregularidad, por definición, presupone que el código del cliente quiere usar esta forma particular de construcción y fomenta la mutabilidad.

Usar la reflexión para esto es simplemente erróneo. Los genéricos en Java son una característica de escritura estática en tiempo de compilación. Los intentos de utilizarlos en tiempo de ejecución son una clara indicación de que algo va mal. La reflexión provoca código detallado, fallas en el tiempo de ejecución, dependencias no verificadas y vulnerabilidades de seguridad. ( Class.forName es particularmente malvado.)


Para Java 8 ....

Hay una buena solución en https://.com/a/36315051/2648077 publicación.

Esto usa la interfaz funcional del Supplier Java 8


Podría hacer esto en una JUnit Test Setup.

Quería probar una fachada de Hibernate, así que estaba buscando una forma genérica para hacerlo. Tenga en cuenta que la fachada también implementa una interfaz genérica. Aquí T es la clase de la base de datos y U es la clave principal. Ifacade<T,U> es una fachada para acceder al objeto de base de datos T con la clave principal U.

public abstract class GenericJPAController<T, U, C extends IFacade<T,U>> { protected static EntityManagerFactory emf; /* The properties definition is straightforward*/ protected T testObject; protected C facadeManager; @BeforeClass public static void setUpClass() { try { emf = Persistence.createEntityManagerFactory("my entity manager factory"); } catch (Throwable ex) { System.err.println("Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } } @AfterClass public static void tearDownClass() { } @Before public void setUp() { /* Get the class name*/ String className = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[2].getTypeName(); /* Create the instance */ try { facadeManager = (C) Class.forName(className).newInstance(); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) { Logger.getLogger(GenericJPAController.class.getName()).log(Level.SEVERE, null, ex); } createTestObject(); } @After public void tearDown() { } /** * Test of testFindTEntities_0args method, of class * GenericJPAController<T, U, C extends IFacade<T,U>>. * @throws java.lang.ClassNotFoundException * @throws java.lang.NoSuchMethodException * @throws java.lang.InstantiationException * @throws java.lang.IllegalAccessException */ @Test public void testFindTEntities_0args() throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException { /* Example of instance usage. Even intellisense (NetBeans) works here!*/ try { List<T> lista = (List<T>) facadeManager.findAllEntities(); lista.stream().forEach((ct) -> { System.out.println("Find all: " + stringReport()); }); } catch (Throwable ex) { System.err.println("Failed to access object." + ex); throw new ExceptionInInitializerError(ex); } } /** * * @return */ public abstract String stringReport(); protected abstract T createTestObject(); protected abstract T editTestObject(); protected abstract U getTextObjectIndex(); }


Solución rápida que funcionó para mí. Veo que ya hay una respuesta para esto y esta puede que ni siquiera sea la mejor manera de hacerlo. Además, para mi solución necesitarás a Gson .

Sin embargo, me encontré con una situación en la que necesitaba crear una instancia de una clase genérica de tipo java.lang.reflect.Type .

El siguiente código creará una instancia de la clase que desee con variables de instancia nulas.

T object = new Gson().fromJson("{}", myKnownType);

Donde myKnownType se conoce de myKnownType y se obtiene a través de TypeToken.getType() .

Ahora puede establecer las propiedades adecuadas en este objeto. De nuevo, esta puede no ser la mejor manera de hacerlo, pero funciona como una solución rápida si eso es lo que necesita.


Una opción es pasar Bar.class (o el tipo que le interese, cualquier forma de especificar la referencia apropiada de Class<T> ) y mantener ese valor como un campo:

public class Test { public static void main(String [] args) throws Exception // Just for simplicity! { Generic<Bar> x = new Generic<Bar>(Bar.class); Bar y = x.buildOne(); } } public class Generic<T> { private Class<T> clazz; public Generic(Class<T> clazz) { this.clazz = clazz; } public T buildOne() throws InstantiationException, IllegalAccessException { return clazz.newInstance(); } } public class Bar { public Bar() { System.out.println("Constructing"); } }

Otra opción es tener una interfaz de "fábrica" ​​y pasar una fábrica al constructor de la clase genérica. Eso es más flexible, y no necesita preocuparse por las excepciones de reflexión.


Y esta es la implementación de Factory, como Jon Skeet sugirió :

interface Factory<T> { T factory(); } class Araba { //static inner class for Factory<T> implementation public static class ArabaFactory implements Factory<Araba> { public Araba factory() { return new Araba(); } } public String toString() { return "Abubeee"; } } class Generic<T> { private T var; Generic(Factory<T> fact) { System.out.println("Constructor with Factory<T> parameter"); var = fact.factory(); } Generic(T var) { System.out.println("Constructor with T parameter"); this.var = var; } T get() { return var; } } public class Main { public static void main(String[] string) { Generic<Araba> gen = new Generic<Araba>(new Araba.ArabaFactory()); System.out.print(gen.get()); } }

Salida:

Constructor with Factory<T> parameter Abubeee