Действительно ли возможно создать экземпляр вложенного класса с помощью Отражения Java?

Образец кода:

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?
    }        
}

Действительно ли возможно создать новый экземпляр класса Панель, дающая ее имя? Я пытался использовать:

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

это находит класс, но когда я использую c.newInstance (), это бросает InstantiationException.

34
задан skaffman 19 January 2010 в 23:23
поделиться

5 ответов

Вам нужно прыгать через несколько обручей, чтобы сделать это. Во-первых, вам необходимо использовать Class.getConstuctor () , чтобы найти объект конструктора , который вы хотите вызвать:

возвращает объект конструктора, который отражает указанную общественность Конструктор класса представлен по этому классу объект. То Параметр Parametertypes - это массив объектов класса, которые определяют Формальные типы параметров конструктора, в заявленном порядке. Если этот класс Объект представляет внутренний класс объявлено в нестатическом контексте, Формальные типы параметров включают явный прикрывающий экземпляр как Первый параметр.

, а затем вы используете Contrector.NewInstance () :

Если класс объявления конструктора это внутренний класс в нестатическом контекст, первый аргумент Конструктор должен быть ограбленным Экземпляр

54
ответ дан 27 November 2019 в 16:16
поделиться

Быстрый и грязный код:

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

Объяснение: Вы должны сообщить бару о его обложении FO.

7
ответ дан 27 November 2019 в 16:16
поделиться

Да. Помните, что вам нужно кормить внешний экземпляр к внутреннему классу. Используйте 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 или позже, теперь неявный) вы получаете задание поля экземпляра перед вызовом Super Constructor (используется незаконным ).

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
2
ответ дан 27 November 2019 в 16:16
поделиться

Другие ответы объяснили, как вы можете сделать то, что вы хотите сделать.

Но я хочу предложить вам, что тот факт, что вам нужно сделать это вообще, является признаком того, что есть что-то не так с вашей системой. Я бы предположил, что вам либо нужен (нестатический) фабричный метод на прилагающий класс, или вам нужно объявить внутренний класс как статический.

Создание (нестатическое) экземпляра внутреннего класса, отражающимся имеет «запах» сломанной инкапсуляции.

1
ответ дан 27 November 2019 в 16:16
поделиться

Внутренние классы действительно могут быть не построены без сначала построения родительского класса. Это не может существовать вне родительского класса. Вам придется пройти экземпляр родительского класса при выполнении размышлений. Вложенные классы статические , и их можно использовать независимо от родительского класса, таким образом, при совершении отражения.

Вот 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[] {});
            }
        }
    }
}

Это должно производить

Nested constructed
Inner constructed
Nested constructed
Inner constructed
Nested constructed
25
ответ дан 27 November 2019 в 16:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: