Java:使用类型参数访问私有构造函数

Posted

技术标签:

【中文标题】Java:使用类型参数访问私有构造函数【英文标题】:Java: accessing private constructor with type parameters 【发布时间】:2011-08-03 12:51:48 【问题描述】:

这是this question about java private constructors 的后续。

假设我有以下课程:

class Foo<T>

    private T arg;
    private Foo(T t) 
        // private!
        this.arg = t;
       

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

如何使用反射构造new Foo("hello")

回答

基于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);
       

【问题讨论】:

它不起作用:( java.lang.NoSuchMethodException: my.package.path.Foo.(java.lang.Object) at java.lang.Class.getConstructor0(Class.java :2892) 在 java.lang.Class.getDeclaredConstructor(Class.java:2058) 在 ProductCatalogAgentTest.testConnect(ProductCatalogAgentTest.java:461) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 【参考方案1】:

起初我使用反射得到 NoSuchMethodException。

使用这个:

Constructor<TestClass> constructor= (Constructor<TestClass>) TestClass.class.getDeclaredConstructors()[0];

【讨论】:

【参考方案2】:

如果 Junit 测试类(在测试文件夹中)与实际类具有相同的包名,那么从 Junit 测试用例中,我们可以调用所有私有方法进行测试,而无需任何额外的库,如 dp4j。

【讨论】:

如果你的类在 src/main/java 文件夹和包中:com.temp(这个类有私有构造函数)假设你的测试类在 src/test/java 文件夹和包中com.temp。在这种情况下,您无法使用测试类访问实际类的私有构造函数。您必须通过 dp4j 库或使用您自己的反射代码来使用反射。【参考方案3】:

如果私有构造函数不带任何参数,那么我们在创建新实例时会获取问题,在这种情况下,在 setAccessible true 之后我们无法创建对象。 即使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:我的博客的“Eager Initialization”和“Singleton Violation by reflection”:http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/

【讨论】:

【参考方案4】:

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

用@Reflect 代替JUnit 的@Test 注释注入反射的方法:

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。

【讨论】:

【参考方案5】:

确保在获取构造函数时使用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);

【讨论】:

我不知道为什么,但我收到一个异常,说我的构造函数不存在(它确实存在)。有任何想法吗? More Info【参考方案6】:

有一个 JUnit 库 (dp4j) 可以自动插入代码以访问私有方法。这可能有用。

【讨论】:

【参考方案7】:

您需要获取类,找到接受单个参数的构造函数,其下限为 T(在本例中为 Object),强制构造函数可访问(使用 setAccessible 方法),最后调用它与所需的参数。

【讨论】:

这篇文章可能会有所帮助:dunwood.blogspot.com/2004/05/…

以上是关于Java:使用类型参数访问私有构造函数的主要内容,如果未能解决你的问题,请参考以下文章

Typescript构造函数和继承

如何限制开发人员使用反射访问Java中的私有方法和构造函数?

java内部私有类的构造函数

如何访问类的私有构造函数?

在 C# 中从类外部访问私有构造函数

Java 类中的哪些变量构造函数可以访问?