2011-11-23 12 views
6

Uso una fábrica de resumen para devolver las instancias de subclasses.I concreto le gustaría crear instancias de las subclases en tiempo de ejecución Dada una cadena del nombre de la clase concreta. También necesito pasar un parámetro a los constructores. La estructura de clase es el siguiente:Java Instantiate clase en tiempo de ejecución con parámetros

abstract class Parent { 

    private static HashMap<String, Child> instances = new HashMap<String,Child>() 

    private Object constructorParameter; 

    public static Child factory(String childName, Object constructorParam){ 

    if(instances.keyExists(childName)){ 
     return instances.get(childName); 
    } 

    //Some code here to instantiate the Child using constructorParam, 
    //then save Child into the HashMap, and then return the Child. 
    //Currently, I am doing: 
    Child instance = (Child) Class.forName(childClass).getConstructor().newInstance(new Object[] {constructorParam}); 
    instances.put(childName, instance); 
    return instance; 
    } 

    //Constructor is protected so unrelated classes can't instantiate 
    protected Parent(Object param){ 
    constructorParameter = param; 
    } 

}//end Parent 

class Child extends Parent { 
    protected Child(Object constructorParameter){ 
     super(constructorParameter); 
    } 
} 

Mi attmept anteriormente está lanzando la siguiente excepción: java.lang.NoSuchMethodException: Child.<init>(), seguido por el seguimiento de la pila.

Cualquier ayuda es apreciada. ¡Gracias!

Respuesta

13
Constructor<?> c = Class.forName(childClass).getDeclaredConstructor(constructorParam.getClass()); 
c.setAccessible(true); 
c.newInstance(new Object[] {constructorParam}); 

El método getConstructor toma Class argumentos para distinguir entre los constructores. Pero solo devuelve constructores públicos, por lo que necesitaría getDeclaredConstructor(..). Entonces necesitaría setAccessible(true)

+0

que probé esto y todavía estoy viendo el mismo error. ¿Debo modificar alguna firma de constructor? Por el momento, las firmas no esperan explícitamente parámetros de tipo Object, sino de algo más específico. – bibs

+0

su 'constructorParam.getClass()' debe devolver el tipo de parámetro exacto que está esperando – Bozho

+0

Basado en su ejemplo, no estoy seguro de lo que hace constructorParam.getClass(). ¿Puedes explicar mejor tu respuesta? ¡Gracias! – trusktr

3

El error: Está invocando el constructor incorrecto, y el compilador no tiene manera de ayudarlo.

El problema que estaba teniendo es simplemente que estaba accediendo al constructor de cero argumentos, en lugar de uno con argumentos. Recuerde que los constructores en Java son en última instancia, sólo métodos, si bien los especiales - y con la reflexión, todas las apuestas están apagadas --- el compilador no le ayudará si usted hace algo tonto. En su caso, tuvo un problema de alcance Y también un problema de firma de método al mismo tiempo.

¿Cómo resolver este problema y no tener que tratar con él de nuevo en esta aplicación

Es una buena idea para envolver invocaciones constructor en un método de ayuda estática que puede ser directamente a prueba, y luego poner una prueba explícita para ellos en mis pruebas unitarias, porque si el constructor cambia y olvidas actualizar tu código de reflexión, volverás a ver estos errores crípticos arrastrándose de nuevo.

también puede simplemente invocar el constructor de la siguiente manera:

public static Child create(Integer i, String s) throws Exception 
{ 
    Constructor c = Class.forName(childClass).getConstructor(new Object[]{Integer.class, String.class}); 
    c.setAccessible(true); 
    Child instance = (Child) c.newInstance(new Object[]{i , s}) ; 
    return instance; 
} 

y por supuesto añadir a sus pruebas

@Test 
    public void testInvoke() 
    { 
     try{ 
    MyClass.create(1,"test"); 
    } 
    catch(Exception e) 
    { 
     Assert.fail("Invocation failed : check api for reflection classes in " + MyClass.class); 
    } 
    } 
+0

¿Dónde pasas los parámetros al constructor aquí? – bibs

+0

@bibs lo siento, dejé ese detalle "menor". La invocación dinámica del constructor, por supuesto, toma una matriz de objetos como sus argumentos, que debe coincidir con la firma del constructor que usted adquiere del método Class.getConstructor ... – jayunit100

Cuestiones relacionadas