2011-04-12 133 views
50

这是this question about java private constructors的后续操作。Java:访问带有类型参数的私有构造函数

假设我有以下类:

​​

我将如何构建一个new Foo("hello")使用反射?

ANSWER

基于jtahlborn's answer,以下工作:

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

它不工作:( java.lang.NoSuchMethodException:my.package.path.Foo (java.lang.Object中) \t在java.lang.Class.getConstructor0(Class.java:2892) \t在java.lang.Class.getDeclaredConstructor(Class.java:2058) \t在ProductCatalogAgentTest.testConnect(ProductCatalogAgentTest.java:461) \t在sun.reflect.NativeMethodAccessorImpl.invoke0(本机方法) – 2015-09-22 23:13:02

回答

23

你需要获取类,发现它只有一个参数与下界T的构造函数(以这种情况下Object),强制构造函数可访问(使用setAccessible方法),最后用所需的参数调用它。

+6

这篇文章可能会有所帮助:HTTP ://dunwood.blogspot.com/2004/05/instantiate-java-class-that-has.html – 2011-04-12 02:57:32

33

确保在获取构造函数时使用getDeclaredConstructors,并将它的可访问性设置为true,因为它是私有的。

这样的事情应该工作。

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

更新

如果你想利用getDeclaredConstructor,合格Object.class作为转换为一个通用的T.

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

我不知道为什么,但我得到一个异常,说我的构造函数不存在(它确实存在) 。 有任何想法吗? [详细信息](https://hastebin.com/usexeqanun.java) – 2017-12-31 08:00:43

1

参数有选择JUnit库(dp4j),它会自动插入用于访问私有方法的代码。这可能是有用的。

3

正如@ArtB表示,如果您知道编译时需要使用的构造函数,则可以使用dp4j.com,。在项目主页上有一个例子,访问一个Singleton构造函数。

相反JUnit的@Test的注释,其中与@Reflect注入思考方法:

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

要看到反射生成的代码使用-Averbose = true参数如this answer

8

那么万一如果私人构造函数没有采取任何参数,那么我们在创建新实例的时候抓取问题,在这种情况下,在setAccessible之后我们不能创建对象。 即使construct.newInstance(null);也不会为无参数构造函数创建对象。

可以我们创建下面的代码使用反射的对象:

public class Singleton { 

    private static Singleton instance = new Singleton(); 

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

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

是我们可以创建上述类的对象。

// 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); 

你可以参考:例2:“心切初始化”和“辛格尔顿违反反射”我的博客:http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/

2

如果JUnit测试类(在测试文件夹)具有相同的包名称的实际的类,然后从Junit测试案例中,我们可以调用所有的私有方法来测试,而不需要像dp4j这样的额外的库。

+0

如果您的类位于src/main/java文件夹中,并且位于package:com.temp中(此类具有私有构造函数),假设您的测试类是在src/test/java文件夹和包com.temp中。在这种情况下,您不能使用测试类访问实际类的私有构造函数。您必须通过dp4j Library或使用自己的反射代码来使用反射。 – 2016-06-06 18:34:21

相关问题