2011-04-12 17 views
50

Este es un seguimiento de this question about java private constructors.Java: acceso al constructor privado con parámetros de tipo

Supongamos que tengo la clase siguiente:

class Foo<T> 
{ 
    private T arg; 
    private Foo(T t) { 
     // private! 
     this.arg = t; 
    } 

    @Override 
    public String toString() { 
     return "My argument is: " + arg; 
    } 
} 

¿cómo iba a construir una reflexión utilizando new Foo("hello")?

RESPUESTA

Basado en jtahlborn's answer, las siguientes obras:

public class Example { 
    public static void main(final String[] args) throws Exception { 
     Constructor<Foo> constructor; 
     constructor = Foo.class.getDeclaredConstructor(Object.class); 
     constructor.setAccessible(true); 
     Foo<String> foo = constructor.newInstance("arg1"); 
     System.out.println(foo); 
    } 
} 
+2

No funciona :( java.lang.NoSuchMethodException:. My.package.path.Foo (java.lang.Object) \t en java.lang.Class.getConstructor0 (Class.java:2892) \t en java.lang.Class.getDeclaredConstructor (Class.java:2058) \t en ProductCatalogAgentTest.testConnect (ProductCatalogAgentTest.java:461) \t en sun.reflect.NativeMethodAccessorImpl.invoke0 (nativo Método) –

Respuesta

23

que se necesita para conseguir la clase, encontrar el constructor que toma un solo argumento con el límite inferior de T (en este caso es Object), fuerza al constructor a ser accesible (usando el método setAccessible), y finalmente invocarlo con el argumento deseado.

+6

Este artículo podría ayudar a: http : //dunwood.blogspot.com/2004/05/instantiate-java-class-that-has.html –

33

Asegúrate de utilizar getDeclaredConstructors al obtener el constructor y establecer su accesibilidad como verdadero ya que es privado.

Algo como esto debería funcionar.

Constructor<Foo> constructor= (Constructor<Foo>) Foo.class.getDeclaredConstructors()[0]; 
constructor.setAccessible(true); 
Foo obj = constructor.newInstance("foo"); 
System.out.println(obj); 

actualización

Si desea hacer uso de getDeclaredConstructor, pasan Object.class como un argumento que se traduce en un T. genérica

Class fooClazz = Class.forName("path.to.package.Foo"); 
Constructor<Foo> constructor = fooClazz.getDeclaredConstructor(Object.class); 
constructor.setAccessible(true); 
Foo obj = constructor.newInstance("foo"); 
System.out.println(obj); 
+0

No estoy seguro de por qué, pero recibo una excepción que dice que mi constructor no existe (existe) . Algunas ideas ? [Más información] (https://hastebin.com/usexeqanun.java) –

1

hay una biblioteca de JUnit (dp4j) que inserta automáticamente código para acceder a métodos privados. Eso puede ser de utilidad.

3

Como @ArtB dijo que podría usar dp4j.com, si conoce el constructor que desea usar en tiempo de compilación. En la página de inicio del proyecto hay un ejemplo de eso, accediendo a un constructor de Singleton.

En lugar de @test de JUnit anotaciones en el método en el que al inyectar la reflexión con @Reflect:

public class Example { 
    @com.dp4j.Reflect 
    public static void main(final String[] args){ 
     Foo<String> foo = new Foo("hello"); 
     System.out.println(foo); 
    } 
} 

Para ver el reflejo generado utilice el código de -Averbose = true argumento como en this answer.

8

Bueno, en caso de que el constructor privado no tome ningún argumento, entonces buscamos un problema al crear una nueva instancia, en este caso después de setAccessible true no podemos crear el objeto. Incluso construct.newInstance(null); no creará objetos para ningún constructor de argumentos.

podemos crear el objeto de código de abajo utilizando la reflexión:

public class Singleton { 

    private static Singleton instance = new Singleton(); 

    /* private constructor */ 
    private Singleton() {} 

    public static Singleton getDefaultInstance() { 
     return instance; 
    } 
} 

Sí se puede crear el objeto de la clase anterior.

// reflection concept to get constructor of a Singleton class. 
Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor(); 

// change the accessibility of constructor for outside a class object creation. 
constructor.setAccessible(true); 

// creates object of a class as constructor is accessible now. 
Singleton secondOb = constructor.newInstance(); 

// close the accessibility of a constructor. 
constructor.setAccessible(false); 

puede hacer referencia: Ejemplo 2: "inicialización Eager" y "Violación Singleton por la reflexión" de mi blog: http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/

2

Si Junit clase de prueba (en la carpeta de prueba) tiene el mismo nombre de paquete a partir del Clase real, luego del caso de prueba Junit, podemos llamar a todos los métodos privados para probar, sin ninguna biblioteca adicional como dp4j.

+0

Si su clase está en la carpeta src/main/java y en el paquete: com.temp (esta clase tiene constructor privado) y digamos que su clase de prueba es en la carpeta src/test/java y en el paquete com.temp. En estos casos, no puede acceder al constructor privado de la clase real con la clase de prueba. Debe usar el reflejo ya sea a través de la biblioteca dp4j o utilizando su propio código de reflexión. –

Cuestiones relacionadas