Механизм отражения Java: следуйте коду, чтобы изучить отражение

Java
Механизм отражения Java: следуйте коду, чтобы изучить отражение

Поиск в WeChat: Code Farmer StayUp

Адрес домашней страницы:gozhuyinglong.github.io

Совместное использование исходного кода:GitHub.com/go Основной бизнес…

1. Введение

В мире ООП все является объектом. То есть мы можем абстрагировать что угодно в объект.

Например, человек может быть абстрагирован в класс Person, новый новый Person () для создания экземпляра объекта; еще один пример утки, Duck может быть абстрагирован в класс, может быть создан экземпляр ...... тогда это не весь класс сам и его можно абстрагировать в класс? Java предоставляет специальный классClass, используемый для описания внутренней информации класса, является основным классом отражения.

На следующем рисунке показано содержание этой статьи:

2. Обзор механизма отражения Java

Отражение Java (Reflection) позволяет приложениямВремя выполненияС помощью API отражения можно получить внутреннюю информацию обо всех классах или интерфейсах, а также напрямую управлять внутренними свойствами и методами любого объекта. Основным классом механизма отражения являетсяjava.lang.Class.

  • После загрузки класса в куче памяти будет сгенерирована область метода.Classтип объекта.
  • ClassКласс не имеет общедоступного конструктора и предоставляется загрузчиком класса.defineClassметод построен. такClassОбъекты не "новые", а полученные с помощью методов.
  • этоClassОбъекты имеют полную структурную информацию для классов, а класс имеет только однуClassобъект.

3. Получите объект класса

ПолучатьClassСуществует четыре типа объектов:

  1. Получено объектом класса;
  2. Получается вызовом класса напрямую через класс;
  3. Получено Class.forName;
  4. Получено из загрузчика классов.

Следующий код показывает, как получить класс PersonClassЧетыре способа объектов:

@Test
public void testClassFor() {

    // 1.通过类实例获取
    Person person = new Person();
    Class<? extends Person> clazz1 = person.getClass();
    System.out.println("01 - " + clazz1);

    // 2.通过类直接调用class获取
    Class<Person> clazz2 = Person.class;
    System.out.println("02 - " + clazz2);

    // 3.通过Class.forName获取
    Class<?> clazz3 = null;
    try {
        clazz3 = Class.forName("io.github.gozhuyinglong.reflection.Person");
    } catch (ClassNotFoundException e) {
        // 当找不到指定类时,会抛出此异常
        e.printStackTrace();
    }
    System.out.println("03 - " + clazz3);

    // 4.通过类加载器获取
    ClassLoader classLoader = this.getClass().getClassLoader();
    Class<?> clazz4 = null;
    try {
        clazz4 = classLoader.loadClass("io.github.gozhuyinglong.reflection.Person");
    } catch (ClassNotFoundException e) {
        // 当找不到指定类时,会抛出此异常
        e.printStackTrace();
    }
    System.out.println("04 - " + clazz4);

    // hashCode相等,说明这四种方式获取的是同一个实例
    System.out.println("05 - " + clazz1.hashCode());
    System.out.println("06 - " + clazz2.hashCode());
    System.out.println("07 - " + clazz3.hashCode());
    System.out.println("08 - " + clazz4.hashCode());

}

Выходной результат:

01 - class io.github.gozhuyinglong.reflection.Person
02 - class io.github.gozhuyinglong.reflection.Person
03 - class io.github.gozhuyinglong.reflection.Person
04 - class io.github.gozhuyinglong.reflection.Person
05 - 721748895
06 - 721748895
07 - 721748895
08 - 721748895

Из приведенного выше вывода видно, что четыреClassобъектhashCodeТо же самое, указывающее на то, что с помощью этих четырех методов получен один и тот же объект.

4. Объекты классов некоторых специальных классов и интерфейсов

Некоторые специальные классы и интерфейсы упоминаются в комментариях к исходному коду:

  • Перечисление — это тип класса.
  • Аннотация — это интерфейс.
  • Массивы также принадлежат отражению какClassкласс объекта. Массивы с одинаковым типом элемента и размерностью также имеют одинаковыеClassобъекты (то есть разные типы элементов или разные измерения массива, чьиClassобъекты тоже разные).
  • Примитивные типы Java (boolean, byte, char, short, int, long, float,double) и ключевые словаvoidтакже выражается какClassобъект.

Для проверки используется следующий код:

@Test
public void testClassOther() {

    // 枚举是一种类
    Class<PersonEnum> clazz1 = PersonEnum.class;
    System.out.println("01 - " + clazz1);

    // 注解是一种接口
    Class<PersonAnnotation> clazz2 = PersonAnnotation.class;
    System.out.println("02 - " + clazz2);

    // 数组也属于一个反应 Class 实例的类
    Person[] personArray3 = new Person[1];
    Class<? extends Person[]> clazz3 = personArray3.getClass();
    System.out.println("03 - " + clazz3);

    // 具有相同元素类型和维数的数组,也具有相同的 Class 实例
    Person[] personArray4 = new Person[4];
    Class<?> clazz4 = personArray4.getClass();

    Person[][] personArray5 = new Person[1][];
    Class<?> clazz5 = personArray5.getClass();

    // 两个一维数组的 hashCode 相等,说明是同一实例
    System.out.println("04 - " + clazz3.hashCode());
    System.out.println("05 - " + clazz4.hashCode());
    // 一维数组与二维数组的 hashCode 不相等,说明不是同一实例
    System.out.println("06 - " + clazz5.hashCode());

    // 原始 Java 类型和关键字 void 也表示为 Class 实例
    Class<Integer> clazz6 = int.class;
    System.out.println("07 - " + clazz6);

    Class<Double> clazz7 = double.class;
    System.out.println("08 - " + clazz7);

    Class<Void> clazz8 = void.class;
    System.out.println("09 - " + clazz8);

}

Выходной результат:

01 - class io.github.gozhuyinglong.reflection.PersonEnum
02 - interface io.github.gozhuyinglong.reflection.PersonAnnotation
03 - class [Lio.github.gozhuyinglong.reflection.Person;
04 - 721748895
05 - 721748895
06 - 1642534850
07 - int
08 - double
09 - void

Из результатов вывода видно, что это точно так, как описано в исходном коде.

5. API отражения Java

Java предоставляет набор API для отражения, API отClassкласс сjava.lang.reflectСостав библиотеки классов. Эта библиотека содержитField,Method,Constructorи так далее. Объекты этих типов создаются JVM во время выполнения для представления соответствующих членов неизвестного класса.

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

Некоторые часто используемые классы описаны ниже:

5.1 Класс

java.lang.ClassКласс используется для описания внутренней информации класса,ClassЭкземпляр класса может получить пакет, аннотацию, модификатор, имя, суперкласс, интерфейс и т. д. класса.

@Test
public void testClass() throws Exception {
    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取该类所在包路径
    Package aPackage = clazz.getPackage();
    System.out.println("01 - " + aPackage);

    // 获取该类上所有注解
    Annotation[] declaredAnnotations = clazz.getDeclaredAnnotations();
    for (Annotation temp : declaredAnnotations) {
        System.out.println("02 - " + temp);
    }

    // 获取类上的修饰符
    int modifiers = clazz.getModifiers();
    String modifier = Modifier.toString(modifiers);
    System.out.println("03 - " + modifier);

    // 获取类名称
    String name = clazz.getName();
    System.out.println("04 - " + name);
    // 获取简单类名
    String simpleName = clazz.getSimpleName();
    System.out.println("05 - " + simpleName);

    // 获取直属超类
    Type genericSuperclass = clazz.getGenericSuperclass();
    System.out.println("06 - " + genericSuperclass);

    // 获取直属实现的接口
    Type[] genericInterfaces = clazz.getGenericInterfaces();
    for (Type temp : genericInterfaces) {
        System.out.println("07 - " + temp);
    }

}

Выходной результат:

01 - package io.github.gozhuyinglong.reflection
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - public final
04 - io.github.gozhuyinglong.reflection.Person
05 - Person
06 - class io.github.gozhuyinglong.reflection.PersonParent
07 - interface io.github.gozhuyinglong.reflection.PersonInterface

5.2 Конструктор

java.lang.reflect.ConstructorПредоставляет информацию о конструкторе класса. Вы можете получить аннотационную информацию, типы параметров и т. д. в конструкторе.

@Test
public void testConstructor() throws Exception {
    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取一个声明为 public 构造函数实例
    Constructor<?> constructor1 = clazz.getConstructor(String.class, int.class, PersonEnum.class);
    System.out.println("01 - " + constructor1);

    // 获取所有声明为 public 构造函数实例
    Constructor<?>[] constructorArray1 = clazz.getConstructors();
    for (Constructor<?> constructor : constructorArray1) {
        System.out.println("02 - " + constructor);
    }

    // 获取一个声明的构造函数实例
    Constructor<?> constructor2 = clazz.getDeclaredConstructor(String.class);
    System.out.println("03 - " + constructor2);

    // 获取所有声明的构造函数实例
    Constructor<?>[] constructorArray2 = clazz.getDeclaredConstructors();
    for (Constructor<?> constructor : constructorArray2) {
        System.out.println("04 - " + constructor);
    }

    // 根据构造函数创建一个实例
    Object o1 = constructor1.newInstance("杨过", 25, PersonEnum.MAN);
    System.out.println("05 - " + o1);

    // 将构造函数的可访问标志设为 true 后,可以通过私有构造函数创建实例
    constructor2.setAccessible(true);
    Object o2 = constructor2.newInstance("小龙女");
    System.out.println("06 - " + o2);

    // 获取该构造函数上的所有注解
    Annotation[] annotations = constructor1.getDeclaredAnnotations();
    for (Annotation annotation : annotations) {
        System.out.println("07 - " + annotation);
    }

    // 获取该构造函数上的所有参数类型
    Type[] genericParameterTypes = constructor1.getGenericParameterTypes();
    for (Type genericParameterType : genericParameterTypes) {
        System.out.println("08 - " + genericParameterType);
    }

}

Выходной результат:

01 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
02 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int)
02 - public io.github.gozhuyinglong.reflection.Person()
03 - private io.github.gozhuyinglong.reflection.Person(java.lang.String)
04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int,io.github.gozhuyinglong.reflection.PersonEnum)
04 - public io.github.gozhuyinglong.reflection.Person(java.lang.String,int)
04 - private io.github.gozhuyinglong.reflection.Person(java.lang.String)
04 - public io.github.gozhuyinglong.reflection.Person()
05 - Person{name='杨过', age=25, sex='MAN'}
06 - Person{name='小龙女', age=0, sex='null'}
07 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
08 - class java.lang.String
08 - int
08 - class io.github.gozhuyinglong.reflection.PersonEnum

5.3 Поле (атрибут)

java.lang.reflect.FieldПредоставляет информацию об атрибутах класса. Вы можете получить аннотации, модификаторы, типы атрибутов, имена атрибутов и т. д. для атрибутов.

@Test
public void testField() throws Exception {

    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取一个该类或父类中声明为 public 的属性
    Field field1 = clazz.getField("hobby");
    System.out.println("01 - " + field1);

    // 获取该类及父类中所有声明为 public 的属性
    Field[] fieldArray1 = clazz.getFields();
    for (Field field : fieldArray1) {
        System.out.println("02 - " + field);
    }

    // 获取一个该类中声明的属性
    Field field2 = clazz.getDeclaredField("name");
    System.out.println("03 - " + field2);

    // 获取该类中所有声明的属性
    Field[] fieldArray2 = clazz.getDeclaredFields();
    for (Field field : fieldArray2) {
        System.out.println("04 - " + field);
    }

    // 获取该属性上的所有注解
    Annotation[] declaredAnnotations = field2.getDeclaredAnnotations();
    for (Annotation declaredAnnotation : declaredAnnotations) {
        System.out.println("05 - " + declaredAnnotation);
    }

    // 获取修饰符
    String modifier = Modifier.toString(field2.getModifiers());
    System.out.println("06 - " + modifier);

    // 获取属性类型,返回类对象
    Class<?> type = field2.getType();
    System.out.println("07 - " + type);
    // 获取属性类型,返回Type对象
    Type genericType = field2.getGenericType();
    System.out.println("08 - " + genericType);

    // 获取属性名称
    String name = field2.getName();
    System.out.println("09 - " + name);

}

Выходной результат:

01 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
02 - public int io.github.gozhuyinglong.reflection.Person.height
02 - public java.lang.String io.github.gozhuyinglong.reflection.PersonParent.hobby
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.name
04 - private int io.github.gozhuyinglong.reflection.Person.age
04 - public int io.github.gozhuyinglong.reflection.Person.height
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - private
07 - class java.lang.String
08 - class java.lang.String
09 - name

5.4 Метод

java.lang.reflect.MethodПредоставляет информацию о методе для класса. Вы можете получить аннотации, модификаторы, типы возвращаемых значений, имена методов и все параметры метода.

@Test
public void testMethod() throws Exception {

    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取一个该类及父类中声明为 public 的方法,需要指定方法的入参类型
    Method method = clazz.getMethod("setName", String.class);
    System.out.println("01 - " + method);

    // 获取该类及父类中所有声明为 public 的方法
    Method[] methods = clazz.getMethods();
    for (Method temp : methods) {
        System.out.println("02 - " + temp);
    }

    // 获取一个在该类中声明的方法
    Method declaredMethod = clazz.getDeclaredMethod("display");
    System.out.println("03 - " + declaredMethod);

    // 获取所有在该类中声明的方法
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method temp : declaredMethods) {
        System.out.println("04 - " + temp);
    }

    // 获取该方法上的所有注解
    Annotation[] declaredAnnotations = method.getDeclaredAnnotations();
    for (Annotation temp : declaredAnnotations) {
        System.out.println("05 - " + temp);
    }

    // 获取修饰符
    String modifier = Modifier.toString(method.getModifiers());
    System.out.println("06 - " + modifier);

    // 获取返回值类型,返回类对象
    Class<?> returnType = method.getReturnType();
    System.out.println("07 - " + returnType);
    // 获取返回值类型,返回Type对象
    Type genericReturnType = method.getGenericReturnType();
    System.out.println("08 - " + genericReturnType);

    // 获取方法名称
    String name = method.getName();
    System.out.println("09 - " + name);

    // 获取所有入参
    Parameter[] parameters = method.getParameters();
    for (Parameter temp : parameters) {
        System.out.println("10 - " + temp);
    }

}

Выходной результат:

01 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
02 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
02 - public int io.github.gozhuyinglong.reflection.Person.getAge()
02 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
02 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
02 - public io.github.gozhuyinglong.reflection.PersonEnum io.github.gozhuyinglong.reflection.PersonParent.getSex()
02 - public void io.github.gozhuyinglong.reflection.PersonParent.setSex(io.github.gozhuyinglong.reflection.PersonEnum)
02 - public final void java.lang.Object.wait() throws java.lang.InterruptedException
02 - public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
02 - public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
02 - public boolean java.lang.Object.equals(java.lang.Object)
02 - public native int java.lang.Object.hashCode()
02 - public final native java.lang.Class java.lang.Object.getClass()
02 - public final native void java.lang.Object.notify()
02 - public final native void java.lang.Object.notifyAll()
03 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.toString()
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.getName()
04 - public void io.github.gozhuyinglong.reflection.Person.setName(java.lang.String)
04 - private java.lang.String io.github.gozhuyinglong.reflection.Person.display()
04 - public int io.github.gozhuyinglong.reflection.Person.getAge()
04 - public void io.github.gozhuyinglong.reflection.Person.setAge(int)
04 - public java.lang.String io.github.gozhuyinglong.reflection.Person.sayHello()
05 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
06 - public
07 - void
08 - void
09 - setName
10 - java.lang.String arg0

5.5 Модификатор

java.lang.reflect.ModifierПредоставляется информация модификатора доступа. пройти черезClass,Field,Method,Constructorи другие объекты могут получить модификатор, этот модификатор доступа является целым числом, к которому можно получить доступ с помощьюModifier.toStringспособ просмотра описания модификатора. И класс предоставляет некоторые статические методы и константы для декодирования модификаторов доступа.

@Test
public void testModifier() throws Exception {
    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取类的修饰符值
    int modifiers1 = clazz.getModifiers();
    System.out.println("01 - " + modifiers1);

    // 获取属性的修饰符值
    int modifiers2 = clazz.getDeclaredField("name").getModifiers();
    System.out.println("02 - " + modifiers2);

    // 获取构造函数的修饰符值
    int modifiers3 = clazz.getDeclaredConstructor(String.class).getModifiers();
    System.out.println("03 - " + modifiers3);

    // 获取方法的修饰符值
    int modifiers4 = clazz.getDeclaredMethod("display").getModifiers();
    System.out.println("04 - " + modifiers4);

    // 判断修饰符值是否 final 类型
    boolean isFinal = Modifier.isFinal(modifiers1);
    System.out.println("05 - " + isFinal);

    // 判断修饰符值是否 public 类型
    boolean isPublic = Modifier.isPublic(modifiers2);
    System.out.println("06 - " + isPublic);

    // 根据修饰符值,获取修饰符标志的字符串
    String modifier = Modifier.toString(modifiers1);
    System.out.println("07 - " + modifier);
    System.out.println("08 - " + Modifier.toString(modifiers2));

}

Выходной результат:

01 - 17
02 - 2
03 - 2
04 - 2
05 - true
06 - false
07 - public final
08 - private

5.6 Параметр

java.lang.reflect.ParameterПредоставляет информацию о параметрах для метода. Вы можете получить аннотации, имена параметров, типы параметров и т. д. в методе.

@Test
public void testParameter() throws Exception {
    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 获取构造函数的参数
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class);
    Parameter[] parameterArray1 = constructor.getParameters();
    for (Parameter temp : parameterArray1) {
        System.out.println("01 - " + temp);
    }

    // 获取方法的参数
    Method method = clazz.getMethod("setName", String.class);
    Parameter[] parameterArray2 = method.getParameters();
    for (Parameter temp : parameterArray2) {
        System.out.println("02 - " + temp);
    }

    Parameter parameter = parameterArray1[0];
    // 获取参数上的注解
    Annotation[] annotationArray = parameter.getAnnotations();
    for (Annotation temp : annotationArray) {
        System.out.println("02 - " + temp);
    }

    // 获取参数名称
    String name = parameter.getName();
    System.out.println("03 - " + name);

    // 获取参数类型
    Type parameterizedType = parameter.getParameterizedType();
    System.out.println("04 - " + parameterizedType);
    Class<?> type = parameter.getType();
    System.out.println("05 - " + type);

}

Выходной результат:

01 - java.lang.String arg0
01 - int arg1
01 - io.github.gozhuyinglong.reflection.PersonEnum arg2
02 - java.lang.String arg0
02 - @io.github.gozhuyinglong.reflection.PersonAnnotation()
03 - arg0
04 - class java.lang.String
05 - class java.lang.String

5.7 AccessibleObject (доступный флаг)

java.lang.reflect.AccessibleObjectКлассField,Methodа такжеConstructorСуперкласс класса.

Этот класс предоставляет возможность проверить управление доступом к классам, методам и конструкторам (например, доступ к закрытым методам разрешен только текущему классу).

Долженпроверка доступаВыполните экземпляр настроек / получения свойств, методов вызова, создание классов / инициализации.

в состоянии пройтиsetAccessibleметод устанавливает флаг доступности вtrue(по умолчаниюfalse), закроетсяпроверка доступа. Таким образом можно получить доступ даже к частным свойствам, методам или конструкторам.

6. Отражен динамически созданными объектами и методами реализации

Вы можете использовать отражение для создания объектов и выполнения методов. См. пример кода ниже:

  • пройти черезClassКатегорияnewInstanceСоздайте экземпляр. (Метод вызывает конструктор без аргументов).
  • через конструкторConstructorкласс создает экземпляр.
  • получить метод, затем передатьinvokeвызываемый метод, первый параметр — это экземпляр, а следующие параметры — это методParameter.
  • Получите поле, потому что поле age является частным, поэтому сделайте его доступным (если его не установить, будет выдано исключение). и черезsetметод назначения.
@Test
public void testInvoke() throws Exception {
    Class<?> clazz = Class.forName("io.github.gozhuyinglong.reflection.Person");

    // 通过Class类的newInstance创建一个实例。(该方法调用无参构造器)
    Object o1 = clazz.newInstance();
    System.out.println("01 - " + o1.toString());

    // 通过构造函数Constructor类创建一个实例
    Constructor<?> constructor = clazz.getConstructor(String.class, int.class, PersonEnum.class);
    Object o2 = constructor.newInstance("杨过", 25, PersonEnum.MAN);
    System.out.println("02 - " + o2.toString());

    // 先获取方法,再通过 invoke 方法来调用,第一个参数为实例,后面参数为方法的Parameter
    Method method = clazz.getMethod("setName", String.class);
    method.invoke(o1, "小龙女");
    System.out.println("03 - " + o1.toString());

    // 获取字段,因为 age 字段是私有的,所以将其设置为可访问(不设置会报异常)。并通过 set 方法来赋值
    Field field = clazz.getDeclaredField("age");
    field.setAccessible(true);
    field.set(o1, 28);
    System.out.println("04 - " + o1.toString());

}

Результаты:

01 - Person{name='null', age=0, sex='null'}
02 - Person{name='杨过', age=25, sex='MAN'}
03 - Person{name='小龙女', age=0, sex='null'}
04 - Person{name='小龙女', age=28, sex='null'}

7. Недостатки отражения

Цитата из официального руководства:docs.Oracle.com/Java Color/Picture О...

Хотя отражение является мощным средством, его не следует использовать небрежно. Если вы можете сделать что-то без использования рефлексии, вам следует избегать этого. Потому что при доступе к коду через отражение есть следующие недостатки.

7.1 Затраты на производительность

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

7.2 Ограничения безопасности

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

7.3 Внутреннее облучение

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

8. Полный код

Пожалуйста, посетите мой Github для получения полного кода.Если он вам полезен, поставьте ⭐, спасибо~~🌹🌹🌹

GitHub.com/go Основной бизнес…

9. Ссылки