34

コードのサンプル:

public class Foo
{
    public class Bar
    {
         public void printMesg(String body)
         {
             System.out.println(body);
         }
    }
    public static void main(String[] args)
    {
         // Creating new instance of 'Bar' using Class.forname - how?
    }        
}

名前を付けてクラス Bar の新しいインスタンスを作成することは可能ですか? 私は使用しようとしました:

Class c = Class.forName("Foo$Bar")

クラスが見つかりますが、c.newInstance() を使用すると InstantiationException がスローされます。

4

7 に答える 7

54

これを行うには、いくつかのフープをジャンプする必要があります。まず、Class.getConstructor()Constructorを使用して、呼び出したいオブジェクトを見つける必要があります。

この Class オブジェクトによって表されるクラスの指定されたパブリック コンストラクターを反映する Constructor オブジェクトを返します。parameterTypes パラメーターは、宣言された順序でコンストラクターの仮パラメーターの型を識別する Class オブジェクトの配列です。この Class オブジェクトが非静的コンテキストで宣言された内部クラスを表す場合、仮パラメーターの型には、最初のパラメーターとして明示的な囲みインスタンスが含まれます。

そして、Constructor.newInstance()を使用します:

コンストラクターの宣言クラスが非静的コンテキストの内部クラスである場合、コンストラクターへの最初の引数は外側のインスタンスである必要があります

于 2010-01-19T23:25:59.787 に答える
25

実際、最初に親クラスを構築しないと、内部クラスを構築することはできません。親クラスの外に存在することはできません。リフレクションを行うときは、親クラスのインスタンスを渡す必要があります。ネストされたクラスはstatic、親クラスから独立して使用できるため、リフレクションを行う場合にも使用できます。

これは、すべてのものを示すSSCCEです。

package mypackage;

import java.lang.reflect.Modifier;

public class Parent {

    public static class Nested {
        public Nested() {
            System.out.println("Nested constructed");
        }
    }

    public class Inner {
        public Inner() {
            System.out.println("Inner constructed");
        }
    }

    public static void main(String... args) throws Exception {
        // Construct nested class the normal way:
        Nested nested = new Nested();

        // Construct inner class the normal way:
        Inner inner = new Parent().new Inner();

        // Construct nested class by reflection:
        Class.forName("mypackage.Parent$Nested").newInstance();

        // Construct inner class by reflection:
        Object parent = Class.forName("mypackage.Parent").newInstance();
        for (Class<?> cls : parent.getClass().getDeclaredClasses()) {
            if (!Modifier.isStatic(cls.getModifiers())) {
                // This is an inner class. Pass the parent class in.
                cls.getDeclaredConstructor(new Class[] { parent.getClass() }).newInstance(new Object[] { parent });
            } else {
                // This is a nested class. You can also use it here as follows:
                cls.getDeclaredConstructor(new Class[] {}).newInstance(new Object[] {});
            }
        }
    }
}

これは生成するはずです

ネストされた構築
内部構造
ネストされた構築
内部構造
ネストされた構築
于 2010-01-19T23:47:54.913 に答える
7

クイックで汚いコード:

Foo.Bar.class.getConstructors()[0].newInstance(new Foo());

説明: Bar に Foo が含まれていることを伝える必要があります。

于 2010-01-19T23:29:16.397 に答える
2

はい。外部インスタンスを内部クラスにフィードする必要があることに注意してください。javapコンストラクターを検索するために使用します。java.lang.reflect.Constructor悪に頼るのではなく、通過する必要がありますClass.newInstance

Compiled from "Foo.java"
public class Foo$Bar extends java.lang.Object{
    final Foo this$0;
    public Foo$Bar(Foo);
    public void printMesg(java.lang.String);
}

javap -cスーパーコンストラクターを呼び出す前にインスタンスフィールドの割り当てを取得するため(仮定-target 1.4または後で、現在は暗黙的です)(以前は違法でした)、コンストラクターで興味深いです。

public Foo$Bar(Foo);
  Code:
   0:   aload_0
   1:   aload_1
   2:   putfield        #1; //Field this$0:LFoo;
   5:   aload_0
   6:   invokespecial   #2; //Method java/lang/Object."<init>":()V
   9:   return
于 2010-01-19T23:24:19.133 に答える
1

他の回答は、あなたがやりたいことをどのようにできるかを説明しています。

しかし、これを行う必要があるという事実は、システム設計に少し問題があることを示していることをお勧めします。外側のクラスに (非静的) ファクトリ メソッドが必要か、内部クラスを静的として宣言する必要があることをお勧めします。

(非静的) 内部クラス インスタンスを反射的に作成すると、カプセル化が壊れたという「におい」がします。

于 2010-01-20T01:28:04.627 に答える
-1

ネストされたクラス (静的内部) の回答: 私の場合、完全修飾名で型を取得する必要があります

Class.forName(somePackage.innerClass$outerClass).getConstructor().newInstance();

' $ ' は非常に重要です!

ドットを使用すると、クラス「package.innerClass.outerClass」の ClassNotFoundException が発生します。例外は紛らわしいです:-(。

于 2013-05-14T10:42:43.790 に答える