简体   繁体   中英

Java: accessing private constructor with type parameters

This is a followup to this question about java private constructors .

Suppose I have the following class:

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

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

How would I construct a new Foo("hello") using reflection?

ANSWER

Based on jtahlborn's answer , the following works:

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

Make sure you use getDeclaredConstructors when getting the constructor and set its accessibility to true since its private.

Something like this should work.

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

Update

If you want to make use of getDeclaredConstructor, pass Object.class as an argument which translates to a generic 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);

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

Well in case if private constructor does not take any argument then we fetch problem while creating new instance, in this case after setAccessible true we can't create object. Even construct.newInstance(null); won't create object for no argument constructor.

can we create object of below code using reflection:

public class Singleton {

    private static Singleton instance = new Singleton();

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

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

Yes we can create the object of above class.

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

You can Refer: Example 2: "Eager Initialization" and "Singleton Violation by reflection" of my blog: http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in-java/

As @ArtB said you could use dp4j.com , if you know the constructor you want to use at compile-time . On the project homepage there's an example of just that, accessing a Singleton constructor.

Instead of JUnit's @Test annotate the method in which to inject the Reflection with @Reflect:

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

To see the reflection generated code use -Averbose=true argument as in this answer .

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

There is a library for JUnit ( dp4j ) that automatically inserts code for accessing private methods. That may be of use.

At first I was getting NoSuchMethodException using reflection.

Use this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM