これは 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")
を構築するにはどうすればよいですか?
[〜#〜] answer [〜#〜]
jtahlbornの答え に基づいて、次のように機能します。
_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);
}
}
_
クラスを取得し、Tの下限(この場合はObject)を持つ単一の引数を取るコンストラクターを見つけ、コンストラクターを強制的にアクセス可能にし(setAccessible
メソッドを使用)、最後に呼び出す必要があります。目的の引数を使用します。
コンストラクターを取得するときはgetDeclaredConstructors
を使用し、プライベートからアクセシビリティをtrueに設定してください。
このような何かが動作するはずです。
Constructor<Foo> constructor= (Constructor<Foo>) Foo.class.getDeclaredConstructors()[0];
constructor.setAccessible(true);
Foo obj = constructor.newInstance("foo");
System.out.println(obj);
更新
GetDeclaredConstructorを使用する場合は、Objective.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);
プライベートコンストラクターが引数を取らない場合は、新しいインスタンスの作成中に問題をフェッチします。この場合、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:私のブログの「熱心な初期化」と「リフレクションによるシングルトン違反」: http://sanjaymadnani.wordpress.com/2014/04/14/singleton-design-pattern-in- Java /
@ArtBが言ったように、コンパイル時に使用したいコンストラクターがわかっている場合は、 dp4j.com 、を使用できます。プロジェクトのホームページには、シングルトンコンストラクターにアクセスするまさにその例があります。
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);
}
}
リフレクションで生成されたコードを確認するには、 this answer のように-Averbose = true引数を使用します。
Junitテストクラス(テストフォルダー内)が実際のクラスと同じパッケージ名を持っている場合、Junitテストケースから、dp4jなどの追加のライブラリなしで、テストするすべてのプライベートメソッドを呼び出すことができます。
プライベートメソッドにアクセスするためのコードを自動的に挿入するJUnitのライブラリ( dp4j )があります。それは役に立つかもしれません。
最初は、リフレクションを使用してNoSuchMethodExceptionを取得していました。
これを使って:
Constructor<TestClass> constructor= (Constructor<TestClass>) TestClass.class.getDeclaredConstructors()[0];