クラス名を使用してインスタンスを作成し、コンストラクターを呼び出す


312

クラス名(動的)を指定して特定のクラスのインスタンスを作成し、そのコンストラクターにパラメーターを渡す方法はありますか?

何かのようなもの:

Object object = createInstance("mypackage.MyClass","MyAttributeValue");

はの"MyAttributeValue"コンストラクタの引数ですMyClass

回答:


497

はい、次のようなものです:

Class<?> clazz = Class.forName(className);
Constructor<?> ctor = clazz.getConstructor(String.class);
Object object = ctor.newInstance(new Object[] { ctorArgument });

もちろん、これは単一の文字列パラメーターに対してのみ機能しますが、簡単に変更できます。

クラス名は完全に修飾された名前でなければなりません。つまり、名前空間を含みます。ネストされたクラスの場合は、1ドルを使用する必要があります(コンパイラーが使用するため)。例えば:

package foo;

public class Outer
{
    public static class Nested {}
}

そのためのClassオブジェクトを取得するには、が必要Class.forName("foo.Outer$Nested")です。


5
newInstance()はvarargsメソッドです(と同様GetConstructor()Object。明示的に-arrayを作成する必要はありません。
ヨアヒムザウアー

18
@Joachim:私はそれが可変引数であることを知っていますが、Object[]引数があるとトリッキーになる可能性があるため、この場合は明示的に配列を作成することを好みます。
Jon Skeet、

2
clazz.getConstructor(String.class); なぜここにString.classがあるのですか?
Umair A. 2014

2
@ニュートラライザー:はい、しかし、動的である必要がない質問に答えていました。
Jon Skeet、2014

3
@JonSkeet私はあなたがどこから来たのか理解しています、しかしそれはそれほど単純ではありません-私はドキュメントを見ましたが混乱しました、そして私がそれをテストしてそれが機能した場合も-わかりましたそれは機能しました-それでも機能しなかった場合問題の原因が設定の不足なのか、それとも私の側の何かなのかわからなかったでしょう。そのような単純な質問をするとき、人々は本当に役立つ便利な情報を投げ込みます。だからこそ、単純に「この方法でうまくいくのであれば、そうです」または「方法がありません」というのが本当に役立ちます。しかし、今私の理解は方法がないということです
ycomp

97

を使用Class.forName()して、Class目的のクラスのオブジェクトを取得できます。

次に、を使用getConstructor()して目的のConstructorオブジェクトを見つけます。

最後に、newInstance()そのオブジェクトを呼び出して新しいインスタンスを取得します。

Class<?> c = Class.forName("mypackage.MyClass");
Constructor<?> cons = c.getConstructor(String.class);
Object object = cons.newInstance("MyAttributeValue");

81

リフレクションを使用できます

return Class.forName(className).getConstructor(String.class).newInstance(arg);

3
デフォルトのコンストラクターを使用している場合は、String.classパラメーター値を削除します。例:return Class.forName(className).getConstructor()。newInstance(arg);
Vijay Kumar 2013

21
@VijayKumar私はあなたが意味するものだと思いますClass.forName(className).getConstructor().newInstance();;)
ピーター・ローリー

14

クラスに空のコンストラクターが1つしかない場合(ActivityまたはFragmentなど、androidクラス):

Class<?> myClass = Class.forName("com.example.MyClass");    
Constructor<?> constructor = myClass.getConstructors()[0];

2
これは私を助けたものです。Constructor<?> ctor = clazz.getConstructor(String.class)うまくいかなかったようです。
レオCハン

8

(つまり)を使用する場合getConstructor(String.lang)、コンストラクターはパブリックとして宣言する必要があります。それ以外の場合NoSuchMethodExceptionはスローされます。

非パブリックコンストラクターにアクセスする場合は、代わりに(ie)を使用する必要がありますgetDeclaredConstructor(String.lang)



4

Class<?>コンストラクタ引数を渡してJavaでオブジェクトを作成する非常に簡単な方法:

ケース1:- ここに、このMainクラスの小さなコードがあります。

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class Main {

    public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {

        // Get class name as string.
        String myClassName = Base.class.getName();
        // Create class of type Base.
        Class<?> myClass = Class.forName(myClassName);
        // Create constructor call with argument types.
        Constructor<?> ctr = myClass.getConstructor(String.class);
        // Finally create object of type Base and pass data to constructor.
        String arg1 = "My User Data";
        Object object = ctr.newInstance(new Object[] { arg1 });
        // Type-cast and access the data from class Base.
        Base base = (Base)object;
        System.out.println(base.data);
    }

}

そして、これがBaseクラス構造です:

public class Base {

    public String data = null;

    public Base() 
    {
        data = "default";
        System.out.println("Base()");
    }

    public Base(String arg1) {
        data = arg1;
        System.out.println("Base("+arg1+")");
    }

}

ケース2:-複数の引数を持つコンストラクターを同様にコーディングし、コンストラクターをコピーできます。たとえば、3つの引数をパラメーターとしてBaseコンストラクターに渡すには、コンストラクターをクラスで作成する必要があり、上記のコードを次のように変更します。

Constructor<?> ctr = myClass.getConstructor(String.class, String.class, String.class);
Object object = ctr.newInstance(new Object[] { "Arg1", "Arg2", "Arg3" }); 

ここで、Baseクラスは次のようになります。

public class Base {

    public Base(String a, String b, String c){
        // This constructor need to be created in this case.
    }   
}

注:- コードで処理する必要があるさまざまな例外を処理することを忘れないでください。


もう1つの方法は、既存のJavaオブジェクトをclone()することです。これにより、既存のJavaオブジェクトのコピーが作成されます。この場合、ディープコピーまたはシャローコピーの概念も処理する必要があります。
Rahul Raina

2

シングルトンパターンに従っているクラスにもかかわらず、誰かがクラスのインスタンスを作成する方法を探しているなら、これを行う方法があります。

// Get Class instance
Class<?> clazz = Class.forName("myPackage.MyClass");

// Get the private constructor.
Constructor<?> cons = clazz.getDeclaredConstructor();

// Since it is private, make it accessible.
cons.setAccessible(true);

// Create new object. 
Object obj = cons.newInstance();

これは、プライベートコンストラクターを使用してシングルトンパターンを実装するクラスでのみ機能します。


1

作成したオブジェクト内のメソッドを呼び出すこともできます。

最初のコンストラクターを呼び出して、作成されたオブジェクトの最初のメソッドを呼び出すことで、オブジェクトを瞬時に作成できます。

    Class<?> c = Class.forName("mypackage.MyClass");
    Constructor<?> ctor = c.getConstructors()[0];
    Object object=ctor.newInstance(new Object[]{"ContstractorArgs"});
    c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);

最初のコンストラクターがStringパラメーターとして使用されていることをどのようにして知っていますか?コンストラクターの順序を変更すると少し面倒になる
Farid

@クラスのドキュメントからの変更
Hatem Badawi

それでもgetConstructor(ClassName.class)ましだと思います。クラスでコンストラクターの順序が変わっても、手動で位置を見つける必要はありません
Farid

@Farid-c.getDeclaredMethods()[0] .invoke(object、Object ... MethodArgs); 場合によっては特別なコンストラクタを指定しますが、これが必要になる場合もありますが、それは正しいです。
Hatem Badawi、

1

別の役立つ答え。getConstructor(params).newInstance(args)を使用するにはどうすればよいですか?

return Class.forName(**complete classname**)
    .getConstructor(**here pass parameters passed in constructor**)
    .newInstance(**here pass arguments**);

私の場合、私のクラスのコンストラクターはパラメーターとしてWebdriverを取るため、以下のコードで使用します。

return Class.forName("com.page.BillablePage")
    .getConstructor(WebDriver.class)
    .newInstance(this.driver);
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.