【问题标题】:Java: accessing private constructor with type parametersJava:使用类型参数访问私有构造函数
【发布时间】: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)

标签: java reflection constructor private


【解决方案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 方法),最后调用它与所需的参数。

          【讨论】:

          猜你喜欢
          • 2021-04-17
          • 1970-01-01
          • 2015-11-05
          • 2011-02-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2015-04-04
          • 2017-07-13
          相关资源
          最近更新 更多