2011-04-12 174 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

相關問題