web-dev-qa-db-ja.com

Java:型パラメーターを使用してプライベートコンストラクターにアクセスする

これは 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);
    }   
}
_
65
dsg

クラスを取得し、Tの下限(この場合はObject)を持つ単一の引数を取るコンストラクターを見つけ、コンストラクターを強制的にアクセス可能にし(setAccessibleメソッドを使用)、最後に呼び出す必要があります。目的の引数を使用します。

28
jtahlborn

コンストラクターを取得するときは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);
45
Mohamed Mansour

プライベートコンストラクターが引数を取らない場合は、新しいインスタンスの作成中に問題をフェッチします。この場合、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 /

9
Sanjay Madnani

@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引数を使用します。

3
simpatico

Junitテストクラス(テストフォルダー内)が実際のクラスと同じパッケージ名を持っている場合、Junitテストケースから、dp4jなどの追加のライブラリなしで、テストするすべてのプライベートメソッドを呼び出すことができます。

2
Coder

プライベートメソッドにアクセスするためのコードを自動的に挿入するJUnitのライブラリ( dp4j )があります。それは役に立つかもしれません。

1
Tobogganski

最初は、リフレクションを使用してNoSuchMethodExceptionを取得していました。

これを使って:

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