Принцип и сценарии применения отражения Java

Java задняя часть

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

  • Статически загруженный класс: new создает объект, который является статически загруженным классом и должен загружать все возможные классы во время компиляции.

  • Динамически загружаемые классы: загружаются во время выполнения

    Отражение — это механизм динамической загрузки классов.

image.png

Преимущества и недостатки отражения

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

3. Понять суть дженериков через размышление

1. Обобщения вступают в силу только во время компиляции.

public class Test {
    public static void main(String[] args) {
        // 1、检验泛型擦除
        List  list1 = new ArrayList();
        List<String> list2 = new ArrayList<String>();
        System.out.println(list1.getClass()==list2.getClass());
    }
}

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

2. Генераторы коллекций предназначены для проверки типов и предотвращения неправильного ввода.

List<String> list2 = new ArrayList<String>();
list2.add("a");
list2.add(20);

Ошибка компиляции: int нельзя преобразовать в java.lang.String

3. Вы можете обойти общую проверку через отражение и добавить элементы разных типов

List<String> list2 = new ArrayList<String>();
list2.add("a");
Class<?> c = list2.getClass();
Method method = c.getDeclaredMethod("add",Object.class);
method.invoke(list2,20);
System.out.println(list2.size());

Результат бега: 2

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

Применение отражения

1. Загрузите драйвер базы данных

//  DriverManager.registerDriver(new com.mysql.cj.jdbc.Driver());
Class.forName("com.mysql.cj.jdbc.Driver");

2. Загрузите файлы конфигурации, такие как xml или свойства

  • Процесс загрузки bean-компонентов Spring в режиме конфигурации XML

    • Загрузить все файлы конфигурации XML или свойств в программе в память
    • Содержимое в xml или свойства анализируется в классе Java, и получается строка байт-кода соответствующего класса сущностей и информация о связанных атрибутах.
    • Используйте механизм отражения для получения экземпляра класса класса на основе этой строки.
    • Динамическая настройка свойств экземпляра

    конфигурационный файл

    className=com.example.reflectdemo.TestInvoke
    methodName=printlnState
    

    класс сущности

    public class TestInvoke {
        private void printlnState(){
            System.out.println("I am fine");
        }
    }
    

    Разобрать содержимое конфигурационного файла

    // 解析xml或properties里面的内容,得到对应实体类的字节码字符串以及属性信息
    public static String getName(String key) throws IOException {
        Properties properties = new Properties();
        FileInputStream in = new FileInputStream("D:\IdeaProjects\AllDemos\language-specification\src\main\resources\application.properties");
        properties.load(in);
        in.close();
        return properties.getProperty(key);
    }
    

    Используйте отражение, чтобы получить экземпляр Class класса сущностей, создать экземпляр объекта класса сущностей и вызвать метод

    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException, IOException, ClassNotFoundException, InstantiationException {
        // 使用反射机制,根据这个字符串获得Class对象
        Class<?> c = Class.forName(getName("className"));
        System.out.println(c.getSimpleName());
        // 获取方法
        Method method = c.getDeclaredMethod(getName("methodName"));
        // 绕过安全检查
        method.setAccessible(true);
        // 创建实例对象
        TestInvoke testInvoke = (TestInvoke)c.newInstance();
        // 调用方法
        method.invoke(testInvoke);
    
    }
    
    

    результат операции:

    image.png