Что такое отражение?

Java

Определение отражения

Эта статья основана на JDK8,официальный сайт ОраклИнтерпретация отражения

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions. The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

Отражение позволяет коду Java обнаруживать информацию о полях, методах и конструкторах загруженных классов и работать с этими полями, методами и конструкторами, используя отражение в рамках ограничений безопасности.

Короче говоря, когда программа Java работает

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

Механизм динамического получения содержимого класса, создания объектов и динамического вызова методов и рабочих свойств объектов называется отражением. Даже если тип объекта неизвестен во время компиляции и файл .class для класса не существует, объект можно создать напрямую посредством отражения.

Преимущество

  • Увеличьте гибкость программы и избегайте записи встроенной логики программы в код
  • Код лаконичен и удобочитаем, что может повысить скорость повторного использования кода.

недостаток

  • По сравнению с прямым вызовом производительность отражения снижается в сценариях с большими объемами.
  • Существуют некоторые внутренние риски и риски безопасности

Использование отражения

Источником отражения является java.lang.Class. Класс Class представляет собой унифицированное описание наших пользовательских классов и встроенных классов JDK. Класс Class хранит информацию о типе класса во время выполнения. В классе Class вы можете получить общедоступную информацию о классе, показанную на следующем рисунке. Класс Class тесно связан с отражением, а класс Class вместе с java.lang.reflect обеспечивает поддержку отражения.在这里插入图片描述Определите два класса Boy и Person, Person в качестве родительского класса Boy, в качестве следующего класса, чтобы продемонстрировать использование этого частичного отражения.

Person.class

public class Person {

    public String name;

    private int age;

    public void talk() {
        System.out.println(name + "is talking");
    }
}

Boy.class

public class Boy extends Person {
	
    public int height;

    private int weight;

    public static String description;

    public Boy() {}

    private Boy(int height) {
        this.height = height;
    }

    public Boy(int height, int weight) {
        this.height = height;
        this.weight = weight;
    }

    public static void playBasketball() {
        System.out.println("play basketball!");
    }

    public static void playBall(String ballType) {
        System.out.println("play " + ballType + "!");
    }

    private void pickUpGirl() {
        System.out.println("pick up girl!");
    }

    public int getWeight() {
        return weight;
    }

    public int getHeight() {
        return height;
    }
}

2.1 Четыре способа получить экземпляр объекта Class

Class<Boy> clazz = Boy.class; // 通过类的 class 属性
Class<?> clazz2 = new Boy().getClass(); // 通过运行时类对象的 getClass 方法获取
Class<?> clazz3 = Class.forName("com.hncboy.corejava.reflection.Boy"); // 通过类的全限定名获取
Class<?> clazz4 = Main.class.getClassLoader().loadClass("com.hncboy.corejava.reflection.Boy"); // 通过类加载器获取 

2.2 Рефлексия для получения основной информации о классе

Основная информация о классе включает модификаторы, ключевые слова класса, имена классов, родительские классы, интерфейсы и другую информацию.

int modifier = clazz.getModifiers(); // 获取类的修饰符
Package pack = clazz.getPackage(); // 获取类的包名
String fullClassName = clazz.getName(); // 获取类的全路径名称
String simpleClassName = clazz.getSimpleName(); // 获取类的简单名称
ClassLoader classLoader = clazz.getClassLoader(); // 获取类的类加载器
Class<?>[] interfacesClasses = clazz.getInterfaces(); // 获取类实现的接口列表
Class<?> superClass = clazz.getSuperclass(); // 获取类的父类
Annotation[] annotations = clazz.getAnnotations(); // 获取类的注解列表

С помощью тестового класса проверьте приведенный выше метод:

public class Test {

    public static void main(String[] args) {
        Class<Boy> clazz = Boy.class;

        // 获取类的修饰符,如果有多个修饰符,取相加后的结果
        int modifiers = clazz.getModifiers();
        System.out.println("modifiers: " + modifiers);
        System.out.println("modifiers toString: " + Modifier.toString(modifiers));

        // 获取类的包名
        Package pack = clazz.getPackage();
        System.out.println("package: " + pack);

        // 获取类的全路径名称:包名 + 类名
        String fullClassName = clazz.getName();
        System.out.println("fullClassName: " + fullClassName);

        // 获取类的简单名称:只有类名
        String simpleClassName = clazz.getSimpleName();
        System.out.println("simpleClassName: " + simpleClassName);

        // 获取类的类加载器
        ClassLoader classLoader = clazz.getClassLoader();
        System.out.println("classLoader: " + classLoader);

        // 获取类实现的接口列表
        Class<?>[] interfacesClasses = clazz.getInterfaces();
        System.out.println("interfacesClasses: " + Arrays.toString(interfacesClasses));

        // 获取类的父类
        Class<?> superClass = clazz.getSuperclass();
        System.out.println("superClass: " + superClass);

        // 获取类的注解列表
        Annotation[] annotations = clazz.getAnnotations();
        System.out.println("annotations: " + Arrays.toString(annotations));
    }
}

Результат прогона следующий:

modifiers: 1
modifiers toString: public
package: package com.hncboy.corejava.reflection
fullClassName: com.hncboy.corejava.reflection.Boy
simpleClassName: Boy
classLoader: sun.misc.Launcher$AppClassLoader@18b4aac2
interfacesClasses: []
superClass: class com.hncboy.corejava.reflection.Person
annotations: []

где getModifiers возвращает модификаторы языка Java для этого класса или интерфейса, закодированные как целое число. проверивjava.lang.reflect.ModifierИз API возвращены результаты следующих типов. Значения всех модификаторов являются результатами бинарных операций. Быстрее всего судить о модификаторах по битовым операциям.在这里插入图片描述

2.2 Отражение операций над полями

Информация о полях хранится в классе Field, который предоставляет информацию об отдельных полях класса или интерфейса, а также о динамическом доступе к ним и переменных, которые можно изменить. Отраженные поля могут быть полями класса (статическими) или полями экземпляра. Общие методы следующие:

Field[] fields = clazz.getFields(); // 获取类中所有的公有字段
Field[] declaredFields = clazz.getDeclaredFields(); // 获取类中定义的字段
Field nameField = clazz.getField("name"); // 获取指定名称的公有字段
Field declaredField = clazz.getDeclaredField("likeDesc"); // 获取指定名称类中定义的字段
int modifiersField = likeDescField.getModifiers(); // 获取字段的修饰
nameField.setAccessible(true); // 指定字段强制访问
nameField.set(person, "hncboy"); // 成员字段赋值(需指定对象)
descriptionField.set(null, "hncboy"); // 静态字段赋值

С помощью тестового класса проверьте приведенный выше метод:

public class Test {

    public static void main(String[] args) throws Exception {
        Class<Boy> clazz = Boy.class;

        // 获取类中所有的公有字段,包含继承的
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        // 获取指定名称的公有字段,包含继承的
        Field nameField = clazz.getField("name");
        System.out.println(nameField);

        // 获取本类中定义的所有字段,不包含继承的,包含私有的
        Field[] declaredFields = clazz.getDeclaredFields();
        for (Field field : declaredFields) {
            System.out.println(field);
        }

        // 获取本类中指定名称类中定义的字段
        Field weightField = clazz.getDeclaredField("weight");
        System.out.println(weightField.getModifiers());

        // 给指定字段赋值(需指定对象)
        Boy boy = clazz.newInstance();
        // 将该字段设置为强制访问
        weightField.setAccessible(true);
        weightField.set(boy, 120);
        System.out.println(boy.getWeight());

        // 静态字段赋值,静态字段不需要指定对象
        Field descField = clazz.getField("description");
        descField.set(null, "静态属性");
        System.out.println(Boy.description);
    }
}

Результат прогона следующий:

public int com.hncboy.corejava.reflection.Boy.height
public static java.lang.String com.hncboy.corejava.reflection.Boy.description
public java.lang.String com.hncboy.corejava.reflection.Person.name
public java.lang.String com.hncboy.corejava.reflection.Person.name
public int com.hncboy.corejava.reflection.Boy.height
private int com.hncboy.corejava.reflection.Boy.weight
public static java.lang.String com.hncboy.corejava.reflection.Boy.description
2
120
静态属性

При прямом доступе к частной частной переменной веса будет сообщено о следующей ошибке, и доступ к частной переменной класса Boy будет невозможен. Разрешения можно включить с помощью setAccessible(логический флаг) в классе java.lang.reflect.AccessibleObject, унаследованном Field.Метод setAccessible отменяет разрешение на проверку доступа к языку Java, вызывая собственный метод setAccessible0.

Exception in thread "main" java.lang.IllegalAccessException: Class com.hncboy.corejava.reflection.Test can not access a member of class com.hncboy.corejava.reflection.Boy with modifiers "private"
	at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
	at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
	at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
	at java.lang.reflect.Field.set(Field.java:761)
	at com.hncboy.corejava.reflection.Test.main(Test.java:41)

2.3 Операция рефлексии над методами

Информация о методе хранится в классе Method, который предоставляет информацию об одном методе класса или интерфейса.информации, так и для отдельных методовДоступ. Отраженные методы могут быть методами класса или методами экземпляра (включая абстрактные методы). Общие методы следующие:

Method[] methods = clazz.getMethods(); // 获取类中所有的公有方法
Method[] declaredMethods = clazz.getDeclaredMethods(); // 获取本类的所有方法
Method talkMethod = clazz.getMethod("talk", String.class); // 获取类中指定名称和参数的公有方法
Method pugMethod = clazz.getDeclaredMethod("pickUpGirls"); // 获取本类中定义的指定名称和参数的方法
int modifiers = pugMethod.getModifiers(); // 获取方法的修饰符
talkMethod.invoke(boy, "I tell you"); // 指定对象进行成员方法的调用
pugMethod.setAccessible(true); // 指定方法的强制访问
pickUpGirlsMethod.invoke(null); // 指定静态方法的调用

С помощью тестового класса проверьте приведенный выше метод:

public class Test {

    public static void main(String[] args) throws Exception {
        Class<Boy> clazz = Boy.class;

        // 获取类中定义的方法,包含继承的(Object)
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }

        // 获取类中指定的方法(无参)
        Method talkMethod = clazz.getMethod("talk");
        System.out.println(talkMethod.getName());
        
        // 获取类中指定的方法(有参)
        Method playMethod = clazz.getMethod("playBall", String.class);
        System.out.println(playMethod.getName());

        // 获取本类中的所有方法,不包含继承,包含私有的
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);
        }

        // 获取本类中特定的的方法
        Method declaredMethod = clazz.getDeclaredMethod("pickUpGirl");
        System.out.println(declaredMethod.getName());

        // 底层是基于构造器的创建无参构造器
        Boy boy = clazz.newInstance();
        // 调用公有有参方法
        playMethod.invoke(boy, "足球");
        // 调用私有无参方法,需要设置强制访问
        declaredMethod.setAccessible(true);
        declaredMethod.invoke(boy);

        // 调用静态方法
        Method playBasketBallMethod = clazz.getDeclaredMethod("playBasketball");
        playBasketBallMethod.invoke(null);
    }
}

Результат прогона следующий:

public static void com.hncboy.corejava.reflection.Boy.playBasketball()
public int com.hncboy.corejava.reflection.Boy.getWeight()
public int com.hncboy.corejava.reflection.Boy.getHeight()
public static void com.hncboy.corejava.reflection.Boy.playBall(java.lang.String)
public void com.hncboy.corejava.reflection.Person.talk()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()
talk
playBall
private void com.hncboy.corejava.reflection.Boy.pickUpGirl()
public static void com.hncboy.corejava.reflection.Boy.playBasketball()
public int com.hncboy.corejava.reflection.Boy.getWeight()
public int com.hncboy.corejava.reflection.Boy.getHeight()
public static void com.hncboy.corejava.reflection.Boy.playBall(java.lang.String)
pickUpGirl
play 足球!
pick up girl!
play basketball!

При получении публичных методов всех родительских классов через getMethods родительский класс класса Boy включает в себя класс Person и класс Object, поэтому всего выводится 14 публичных методов. Когда метод getMethod или getDeclaredMethod получает метод с указанным именем метода без параметров, параметры могут быть опущены, а имя метода передается напрямую. При получении метода с параметрами, если тип неверен, будет исключено исключение NoSuchMethodException. сообщается, как показано ниже. Передайте объект экземпляра, чтобы вызвать метод экземпляра через метод вызова метода, и вызовите статический метод и передайте значение null.

Exception in thread "main" java.lang.NoSuchMethodException: com.hncboy.corejava.reflection.Boy.playBall(int)
	at java.lang.Class.getMethod(Class.java:1786)
	at com.hncboy.corejava.reflection.Test.main(Test.java:29)

2.4 Отражение работы конструктора

Информация о конструкторе хранится в классе Constructor, который предоставляет информацию об отдельных конструкторах класса, а также о доступе к классу. Общие методы следующие:

Constructor<?>[] constructors = clazz.getConstructors(); // 获取类中所有的公有构造器
Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors(); // 获取类中所有的构造器
Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(); // 获取类中无参的构造器
Constructor<?> constructor = clazz.getDeclaredConstructor(String.class, String.class); // 获取类中有参构造器
int modifiers = constructor.getModifiers(); // 获取构造器的修饰符
declaredConstructor.newInstance(); // 构造器实例对象
declaredConstructor.setAccessible(true); // 指定构造器的强制访问
constructor.newInstance("hncboy"); // 有参构造调用
clazz.newInstance(); // 直接调用默认无参构造

С помощью тестового класса проверьте приведенный выше метод:

public class Test {

    public static void main(String[] args) throws Exception {
        Class<Boy> clazz = Boy.class;

        // 获取类中所有的公有构造器
        Constructor<?>[] constructors = clazz.getConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }

        // 获取类中所有的构造器,包含私有的
        Constructor<?>[] declaredConstructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : declaredConstructors) {
            System.out.println(constructor);
        }

        // 获取类中无参的构造器
        Constructor<?> noParamsConstructor = clazz.getDeclaredConstructor();
        System.out.println(noParamsConstructor);

        // 获取类中指定参数构造器
        Constructor<?> constructor1 = clazz.getDeclaredConstructor(int.class);
        Constructor<?> constructor2 = clazz.getDeclaredConstructor(int.class, int.class);
        System.out.println(noParamsConstructor.getModifiers());
        System.out.println(constructor1.getModifiers());
        System.out.println(constructor2.getModifiers());

        // 调用构造器
        Boy boy = (Boy) noParamsConstructor.newInstance();
        System.out.println(boy);
        constructor1.setAccessible(true);
        boy = (Boy) constructor1.newInstance(177);
        System.out.println(boy.getHeight());
    }
}

Результат прогона следующий:

public com.hncboy.corejava.reflection.Boy(int,int)
public com.hncboy.corejava.reflection.Boy()
public com.hncboy.corejava.reflection.Boy(int,int)
private com.hncboy.corejava.reflection.Boy(int)
public com.hncboy.corejava.reflection.Boy()
public com.hncboy.corejava.reflection.Boy()
1
2
1
com.hncboy.corejava.reflection.Boy@4b67cf4d
177

Метод getConstructors получает все общедоступные конструкторы в классе, конструкторы не могут быть унаследованы, все могут получить только те, что в этом классе. getDeclaredConstructors Получает все конструкторы этого класса, включая закрытые. При получении конкретного конструктора параметров передаваемые параметры должны совпадать с параметрами конструктора, например, int.class не может быть записан как Integer.class, так как во время компиляции выполняется автоматическая распаковка, а во время выполнения выполняется отражение. .

Посредством отражения объекты могут быть созданы с помощью Class.newInstance() или Constructor.newInstance() . NewInstance в классе Class является слабым типом и может вызывать только конструктор без параметров. Если нет конструктора по умолчанию, будет создано InstantiationException. Исходный код показывает, что метод по существу возвращает tmpConstructor.newInstance((Object[ ])null); , который также вызывает метод newInstance конструктора. NewInstance класса Constructor может вызывать конструктор с любыми параметрами.

3. Отражение уничтожает синглтоны

одноэлементный шаблон

  • частный конструктор
  • Глобально уникальная общедоступная точка доступа
  • Предоставьте статический метод для получения экземпляра извне

3.1 Определение голода

public class Hungry {

    private static final Hungry INSTANCE = new Hungry();

    private Hungry() {}

    public static Hungry getInstance() {
        return INSTANCE;
    }
}

3.2 Определение ленивого ленивого

public class Lazy {

    private static Lazy instance;

    private Lazy() {}

    public static Lazy getInstance() {
        if (instance == null) {
            synchronized (Lazy.class) {
                if (instance == null) {
                    instance = new Lazy();
                }
            }
        }
        return instance;
    }
}

3.3 Определение SingletonDestroyer

public class SingletonDestroyer {

    public static void main(String[] args) throws Exception {
        // 破坏懒汉模式
        Lazy lazyInstance = Lazy.getInstance();
        Constructor<Lazy> lazyConstructor = Lazy.class.getDeclaredConstructor();
        lazyConstructor.setAccessible(true);
        Lazy lazyInstanceReflect = lazyConstructor.newInstance();
        System.out.println(lazyInstance);
        System.out.println(lazyInstanceReflect);

        // 破坏饿汉模式
        Hungry hungryInstance = Hungry.getInstance();
        Constructor<Hungry> hungryConstructor = Hungry.class.getDeclaredConstructor();
        hungryConstructor.setAccessible(true);
        Hungry hungryInstanceReflect = hungryConstructor.newInstance();
        System.out.println(hungryInstance);
        System.out.println(hungryInstanceReflect);
    }
}

Результаты операции следующие: шаблон singleton можно разбить через механизм отражения, а приватный конструктор можно заставить создавать объекты через обязательный доступ.

com.hncboy.corejava.reflection.Lazy@4b67cf4d
com.hncboy.corejava.reflection.Lazy@7ea987ac
com.hncboy.corejava.reflection.Hungry@12a3a380
com.hncboy.corejava.reflection.Hungry@29453f44

В-четвертых, отражение реализует простое создание экземпляра Spring IOC Bean.

IOC (инверсия управления) Инверсия управления — это дизайнерская идея, а не фактическая технология.Основная идея состоит в том, чтобы дать программе (контейнеру IOC) контроль над созданием предварительно разработанных экземпляров объекта. Контейнер IOC, по сути, является картой структур K-V. Принцип реализации IOC — фабричный режим плюс механизм отражения.

пройти черезSpringВ документации рассматриваются три способа создания экземпляра компонента:

  • Создание экземпляра с помощью конструктора
  • Создание экземпляра с использованием метода фабрики экземпляров
  • Создание экземпляра с использованием метода фабрики экземпляров

Действуйте следующим образом:

4.1 Добавьте три класса A, B, C

public class A {

    public A() {
        System.out.println("调用 A 的无参构造器");
    }

    public static B createBInstance() {
        System.out.println("调用 A 的静态方法 createBInstance");
        return new B();
    }

    public C createCInstance() {
        System.out.println("调用 A 的实例方法 createCInstance");
        return new C();
    }
}

class B {}
class C {}

4.2 Добавьте spring-ioc.xml

Создание объектов путем имитации файла конфигурации

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!-- 创建方式1:无参构造器创建 A 对象-->
    <bean id="a" class="com.hncboy.corejava.reflection.A"/>

    <!-- 创建方式2:静态工厂创建,调用 A 的 createBObj 方法来创建名为 b 的对象放入容器 -->
    <bean id="b" class="com.hncboy.corejava.reflection.A" factory-method="createBInstance"/>

    <!-- 创建方式3:实例工厂创建,调用实例 a 的 createBObj 方法来创建名为 c 的对象放入容器 -->
    <bean id="c" factory-bean="a" factory-method="createCInstance"/>

</beans>

4.3 Добавить BeanConfig

/**
 * 存放 bean 的基本信息
 */
public class BeanConfig {

    private String id;
    private String clazz;
    private String factoryMethod;
    private String factoryBean;
    
	/* getter、setter 省略 */
}

4.4 Добавить IOCContainer

/**
 * 定义 map 存放 map
 */
public class IOCContainer {

    private static Map<String, Object> container = new HashMap<>();

    public static void putBean(String id, Object object) {
        container.put(id, object);
    }

    public static Object getBean(String id) {
        return container.get(id);
    }
}

4.5 Добавить инициализацию

Метод создания 1: создается конструктором без аргументов. Содержимое бина включает id и clazz

Способ создания 2: создание статической фабрики. Содержимое бина включает id и factory-method

Способ создания 3: Создание фабрики экземпляров. Содержимое bean-компонента включает идентификатор, factory-bean и factory-method.

public class Init {

    public static void main(String[] args) throws Exception {
        List<BeanConfig> beanConfigs = parseXmlToBeanConfig();
        // 将解析的 BeanConfig 进行实例化
        for (BeanConfig beanConfig : beanConfigs) {
            if (beanConfig.getClazz() != null) {
                Class<?> clazz = Class.forName(beanConfig.getClazz());
                if (beanConfig.getFactoryMethod() != null) {
                    // 创建方式2:静态工厂创建
                    Method method = clazz.getDeclaredMethod(beanConfig.getFactoryMethod());
                    IOCContainer.putBean(beanConfig.getId(), method.invoke(null));
                } else {
                    // 创建方式1:无参构造器创建
                    IOCContainer.putBean(beanConfig.getId(), clazz.newInstance());
                }
            } else if (beanConfig.getId() != null) {
                // 创建方式3:实例工厂创建
                Object object = IOCContainer.getBean(beanConfig.getFactoryBean());
                Method method = object.getClass().getDeclaredMethod(beanConfig.getFactoryMethod());
                IOCContainer.putBean(beanConfig.getId(), method.invoke(object));
            } else {
                System.out.println("缺少配置,无法创建对象!");
            }
        }
    }

    /**
     * 模拟解析 XML 中的 bean
     *
     * @return
     */
    private static List<BeanConfig> parseXmlToBeanConfig() {
        List<BeanConfig> beanConfigs = new ArrayList<>();
        // 模拟无参构造器创建对象
        BeanConfig beanConfig1 = new BeanConfig();
        beanConfig1.setId("a");
        beanConfig1.setClazz("com.hncboy.corejava.reflection.A");
        beanConfigs.add(beanConfig1);

        // 模拟静态工厂创建对象
        BeanConfig beanConfig2 = new BeanConfig();
        beanConfig2.setId("b");
        beanConfig2.setClazz("com.hncboy.corejava.reflection.A");
        beanConfig2.setFactoryMethod("createBInstance");
        beanConfigs.add(beanConfig2);

        // 模拟实例工厂创建对象
        BeanConfig beanConfig3 = new BeanConfig();
        beanConfig3.setId("c");
        beanConfig3.setFactoryBean("a");
        beanConfig3.setFactoryMethod("createCInstance");
        beanConfigs.add(beanConfig3);

        return beanConfigs;
    }
}

Результаты приведены ниже:

调用 A 的无参构造器
调用 A 的静态方法 createBInstance
调用 A 的实例方法 createCInstance

Отражение Java полностью проанализировано

Углубленный анализ отражения Java