Мысли и функции рефлексии
Если есть отрицательное, должно быть и положительное, как инь и ян в мире, 0 и 1 в компьютере. Небеса перевоплощаются, небеса...(Здесь сетка будет слепой биби)
Прежде чем изучать отражение, давайте разберемсяОрточто. Обычно мы используем наиболееnew
Способ создания экземпляра объекта является проявлением орто. Если мне нужно создать экземплярHashMap
, код будет выглядеть так.
Map<Integer, Integer> map = new HashMap<>();
map.put(1, 1);
Однажды я обнаружил, что эта программа не подходит для хранения пар ключ-значение с помощью HashMap, и я предпочитаю использовать HashMap для хранения пар ключ-значение.LinkedHashMap
место хранения. После переписывания кода он выглядит следующим образом.
Map<Integer, Integer> map = new LinkedHashMap<>();
map.put(1, 1);
Если однажды обнаружится, что данные все еще подходят для хранения с помощью HashMap, нужно ли вам повторно модифицировать исходный код?
Нашли проблему? Каждый раз, когда мы меняем потребность, нам приходится зановоИзменить исходный код, затем скомпилируйте код, упакуйте его и перезапустите проект на JVM. После этих шагов эффективность очень низкая.
для этогоТребования меняются часто, но незначительноВ сценарии частая смена исходного кода — определенно недопустимая операция, мы можем использовать开关
, чтобы определить, когда какую структуру данных использовать.
public Map<Integer, Integer> getMap(String param) {
Map<Integer, Integer> map = null;
if (param.equals("HashMap")) {
map = new HashMap<>();
} else if (param.equals("LinkedHashMap")) {
map = new LinkedHashMap<>();
} else if (param.equals("WeakHashMap")) {
map = new WeakHashMap<>();
}
return map;
}
путем передачи параметровparam
Решение о том, какую структуру данных использовать, может быть принято, когда проект запускаетсяДинамические входящие параметрыРешите, какую структуру данных использовать.
Если вы хотите использовать его когда-нибудьTreeMap
, или не может избежать недостатков изменения исходного кода и повторной компиляции и выполнения. В настоящее время,отражениеЭто пригодилось.
Перед запуском кода мынеуверенныйКакая структура данных будет использоваться в будущем, зависит от программывремя выполнениякакой класс данных использовать и反射
допустимыйпроцесс выполнения программыСредне динамичныйПолучить информацию о классеивызов метода класса. При создании экземпляра класса посредством отражения код будет развиваться следующим образом.
public Map<Integer, Integer> getMap(String className) {
Class clazz = Class.forName(className);
Consructor con = clazz.getConstructor();
return (Map<Integer, Integer>) con.newInstance();
}
Независимо от того, какая карта используется, пока она реализованаMap接口
, ты можешь использовать全类名路径
Передайте его в метод, чтобы получить соответствующий экземпляр карты. Например, java.util.HashMap / java.util.LinkedHashMap Если вы хотите создать другие классы, такие какWeakHashMap
,Я такжеНет необходимости изменять приведенный выше исходный код.
Давайте рассмотрим, какnew
Объект создается с помощью反射
из.
- Когда отражение не используется, построение объектов осуществляется новым методом, который используется ввремя компиляцииМожно определить тип объекта.
- Если требования меняются и необходимо создать другой объект, исходный код необходимо изменить, что очень неэстетично, поэтому мы используем
开关
, чтобы определить, какой объект должен быть построен во время работы программы, вы можетеизменить переключательдля создания различных структур данных. - Если есть другие расширенные классы, которые, вероятно, будут использоваться, они будут созданыочень много ответвлений, и не знаю, какие еще классы используются при кодировании, если в будущем
Map
Дополнительный класс коллекции под интерфейсомxxxHashMap
, вы должны создать ветку, которая приводит к размышлению: вы можете运行时
Только определите, какой класс данных использовать.При переключении классов нет необходимости повторно модифицировать исходный код и компилировать программу.
Краткое содержание главы 1:
- ОтраженныйМысль:Типы классов данных определяются и разрешаются во время выполнения программы.
- Отраженныйэффект: для
编译期
Сценарии, в которых невозможно определить, какой класс данных использовать, с помощью反射
пока программа работаетСоздание различных экземпляров класса данных.
Основное использование отражения
Есть 4 основных компонента отражения Java:
-
Class
: любой класс, работающий в памяти, является экземпляром объекта класса Class, и каждый объект класса Class содержит исходный объект.Вся информация. Запомни предложение, делай что-нибудь через размышление, сначала найди класс! -
Field
: описывает классАтрибуты, который содержит всю информацию о свойстве, напримертип данных, имя свойства, модификатор доступа······ -
Constructor
: описывает классМетод строительства, который содержит всю информацию о конструкторе, такую кактип параметра, имя параметра, модификатор доступа······ -
Method
: описывает классвсе методы(включая абстрактные методы), который внутренне содержит всю информацию о методе, иConstructor
Аналогично, за исключением того, что метод имееттип возвращаемого значенияинформацию, потому что конструкторы не возвращают значение.
Я обобщил карту мозга и поместил ее ниже.Если используется рефлексия, то она неотделима от этого ядра4
Класс, только чтобы понять, какую информацию они предоставляют внутри, какую роль они имеют, и использовать их.легкий.
По мере того, как мы изучаем основы использования рефлексии, я буду использоватьSmallPineapple
Класс описывается как шаблон, для начала ознакомимся с основным составом этого класса:Свойства, конструкторы и методы
public class SmallPineapple {
public String name;
public int age;
private double weight; // 体重只有自己知道
public SmallPineapple() {}
public SmallPineapple(String name, int age) {
this.name = name;
this.age = age;
}
public void getInfo() {
System.out.print("["+ name + " 的年龄是:" + age + "]");
}
}
Есть много применений в отражении, и общие функции следующие:
- Получить классОбъект класса
- Создает класс во время выполнениясозданный объект
- Получить всю информацию о классе во время выполнения:Переменные, методы, конструкторы, аннотации
Получить объект класса класса
В Java каждый класс будет иметь свой собственный объект класса, когда мы закончим писать.java
файл, использоватьjavac
После компиляции создается файл байт-кода.class
, содержит всю информацию о классе в файле байт-кода, например属性
,构造方法
,方法
Когда файл байт-кода загружается в виртуальную машину для выполнения, в памяти будет сгенерирован объект класса, который содержит всю информацию внутри класса, которую можно получить при работе программы.
Методы получения объекта класса:3
своего рода:
-
类名.class
: этот метод доступа доступен только в编译
Тип класса был объявлен до того, как получить объект класса
Class clazz = SmallPineapple.class;
-
实例.getClass()
: получить объект класса экземпляра, создав экземпляр объекта
SmallPineapple sp = new SmallPineapple();
Class clazz = sp.getClass();
-
Class.forName(className)
: по классамполное имяПолучить объект класса класса
Class clazz = Class.forName("com.bean.smallpineapple");
получитьClass
субъект может делать с ним все, что захочет: отогнуть (получитьинформация о классе), направляя его на действия (вызывая егометод), увидеть все это (получитьАтрибуты), короче, у него нет конфиденциальности.
Однако в программе есть только один объект класса для каждого класса, а значит, у вас есть только этот奴隶
. Мы используем три вышеуказанных метода для тестирования и печатаем каждыйClass
Объекты все одинаковые.
Class clazz1 = Class.forName("com.bean.SmallPineapple");
Class clazz2 = SmallPineapple.class;
SmallPineapple instance = new SmallPineapple();
Class clazz3 = instance.getClass();
System.out.println("Class.forName() == SmallPineapple.class:" + (clazz1 == clazz2));
System.out.println("Class.forName() == instance.getClass():" + (clazz1 == clazz3));
System.out.println("instance.getClass() == SmallPineapple.class:" + (clazz2 == clazz3));
Причина, по которой в памяти находится только один объект Class
JVM 类加载机制
из双亲委派模型
, что гарантирует, что при запуске программы加载类
Каждый класс будет генерировать только один в памятиClass对象
. Я не буду здесь подробно объяснять, можно просто понять, что JVM помогает нам обеспечитьКласс имеет не более одного объекта класса в памяти..
Создает экземпляр объекта класса
Построение экземпляра класса путем отражения имеет2
своего рода:
- Вызов объекта класса
newInstance()
метод
Class clazz = Class.forName("com.bean.SmallPineapple");
SmallPineapple smallPineapple = (SmallPineapple) clazz.newInstance();
smallPineapple.getInfo();
// [null 的年龄是:0]
Даже если в SmallPineapple явно определен конструктор, в экземпляре, созданном с помощью newInstance(), все значения свойств имеют соответствующий тип初始值
, потому что newInstance() при создании экземпляравызвать конструктор без аргументов по умолчанию.
- Вызов конструктора конструктора
newInstance()
метод
Class clazz = Class.forName("com.bean.SmallPineapple");
Constructor constructor = clazz.getConstructor(String.class, int.class);
constructor.setAccessible(true);
SmallPineapple smallPineapple2 = (SmallPineapple) constructor.newInstance("小菠萝", 21);
smallPineapple2.getInfo();
// [小菠萝 的年龄是:21]
Укажите приобретение с помощью метода getConstructor(Object... paramTypes)Укажите тип параметраКонструктор, когда Конструктор вызывает newInstance(Object... paramValues), передается значение параметров конструктора, и экземпляр также может быть создан, и внутренние свойства были назначены.
пройти черезClass
Объект, вызывающий newInstance(), перейдетКонструктор без аргументов по умолчанию, если вы хотите пройтиявный конструкторЧтобы создать экземпляр, вам нужно заранее вызвать его из класса.getConstructor()
Метод получает соответствующий конструктор и создает экземпляр объекта через конструктор.
Эти API чаще всего встречаются в разработке, и, конечно, есть также очень перегруженные методы.Из-за длины этой статьи, и если каждый метод объясняется один за другим, мы не можем его запомнить, поэтому, когда мы его используем , иди в класс Достаточно заглянуть внутрь.
Получить всю информацию о классе
Объект Class содержит всю информацию о классе. Информация, которую мы можем видеть во время компиляции, — это переменные, методы и конструкторы класса, которые также чаще всего получают во время выполнения.
Получить переменную (поле) в классе
- Field[] getFields(): Получить все поля в классе
public
Все переменные украшены - Поле getField (имя строки): согласноимя переменнойПолучить переменную в классе, котораяПеременные должны быть изменены публичными
- Field[] getDeclaredFields(): получить все переменные в классе, ноНе удалось получить унаследованную переменную
- Поле getDeclaredField(String name): Получить переменную в классе по имени,Не удалось получить унаследованную переменную
Получить метод в классе (Метод)
-
Method[] getMethods(): получить
public
Все способы модификации -
Метод getMethod (имя строки, класс... > paramTypes): согласноимя и тип параметраПолучить соответствующий метод, который должен быть
public
ретушь -
Метод [] getDeclaredMethods(): получить
所有
метод, ноНе удалось получить унаследованный метод -
Метод getDeclaredMethod (имя строки, класс... > paramTypes): согласноимя и тип параметраполучить соответствующий метод,Не удалось получить унаследованный метод
Получить конструктор класса (Constructor)
- Constructor[] getConstructor(): Получить все объекты в классе
public
украшенный конструктор - Конструктор getConstructor(Class...> paramTypes): согласно
参数类型
Получить конструктор в классе, конструктор должен бытьpublic
ретушь - Constructor[] getDeclaredConstructors(): Получить все конструкторы в классе
- Конструктор getDeclaredConstructor(class...> paramTypes): согласно
参数类型
Получить соответствующий конструктор
Каждая функция внутренне подразделяется на заявленные2
своего рода:
имеют
Declared
Измененный метод: вы можете получить содержимое, содержащееся внутри класса.всепеременные, методы и конструкторы, ноНевозможно получить унаследованную информациюникто
Declared
Модифицированный метод: можно получить в этом классеpublic
Модифицированные переменные, методы и конструкторы, которые могутПолучить наследственную информацию
Если вы хотите получить **все (включая наследование)** переменные, методы и конструкторы в классе, вам нужно вызывать одновременноgetXXXs()
иgetDeclaredXXXs()
два метода, используяSet
Коллекции хранят переменные, конструкторы и методы, которые они получают, на случай, если два метода получат одно и то же.
Например: чтобы получить SmallPineapple, зайдите в классвсе переменные, код должен быть написан следующим образом.
Class clazz = Class.forName("com.bean.SmallPineapple");
// 获取 public 属性,包括继承
Field[] fields1 = clazz.getFields();
// 获取所有属性,不包括继承
Field[] fields2 = clazz.getDeclaredFields();
// 将所有属性汇总到 set
Set<Field> allFields = new HashSet<>();
allFields.addAll(Arrays.asList(fields1));
allFields.addAll(Arrays.asList(fields2));
Я не знаю, нашел ли ты егоИнтересные вещи, если свойство родительского класса использует
protected
Ретушь с использованием отражениянедоступноиз.Область действия защищенного модификатора: разрешено только
同一个包下
или子类
Доступ, который может быть унаследован подклассами.getFields() может получить только поля этого класса
public
Переменное значение свойства;getDeclaredFields() может получить толькоВсе свойства этого класса, кроме наследования; переменная, измененная защищенным атрибутом родительского класса, все равно не может быть получена, но она существует в дочернем классе.
получить аннотации
Аннотации Get выкручиваются отдельно, потому что это не какая-то информация, специфичная для объектов Class, каждая переменная, метод и конструктор могут быть модифицированы аннотациями, так что в отражении объекты класса Field, Constructor и Method могут вызывать следующее Эти методы get аннотации к ним.
- Annotation[] getAnnotations(): получитьВсе аннотации
- Аннотация getAnnotation (класс annotaionClass): входящий
注解类型
, получить конкретную аннотацию к объекту - Annotation[] getDeclaredAnnotations(): получает все аннотации, явно отмеченные на объекте, но не может их получить
继承
заметка вниз - Аннотация getDeclaredAnnotation (класс annotationClass): согласно
注解类型
, получить конкретную аннотацию к объекту, не могу получить继承
заметка вниз
только аннотированный@Retension
отмечен какRUNTIME
Когда аннотацию можно получить посредством отражения, @Retension имеет3
Стратегия сохранения:
-
SOURCE
: Сохранить только в **исходный файл (.java)**, то есть аннотация останется только в исходном файле,Компилятор игнорирует эту аннотацию при компиляции, такие как аннотация @Override -
CLASS
:Сохранить какФайл байт-кода (.class)аннотации следуют за файлом байт-кода при компиляции, ноВремя выполненияАннотация не будет обработана -
RUNTIME
: сохранить доВремя выполнения,Одна из наиболее часто используемых стратегий сохранения, вы можете получить всю информацию об аннотации во время выполнения
Как и в приведенном ниже примере, класс SmallPineapple расширяет абстрактный классPineapple
,getInfo()
Метод помечен аннотацией @Override и помечен в подклассе@Transient
Annotation, получить все аннотации к методу переопределения подкласса во время выполнения, вы можете получить только@Transient
Информация.
public abstract class Pineapple {
public abstract void getInfo();
}
public class SmallPineapple extends Pineapple {
@Transient
@Override
public void getInfo() {
System.out.print("小菠萝的身高和年龄是:" + height + "cm ; " + age + "岁");
}
}
стартовый классBootstrap
Получите аннотационную информацию о методе getInfo() в классе SmallPineapple:
public class Bootstrap {
/**
* 根据运行时传入的全类名路径判断具体的类对象
* @param path 类的全类名路径
*/
public static void execute(String path) throws Exception {
Class obj = Class.forName(path);
Method method = obj.getMethod("getInfo");
Annotation[] annotations = method.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
public static void main(String[] args) throws Exception {
execute("com.pineapple.SmallPineapple");
}
}
// @java.beans.Transient(value=true)
Вызов метода через отражение
После получения объекта класса Method посредством отражения вы можете вызвать его, вызвавinvoke
метод выполняется.
-
invoke(Oject obj, Object... args)
: параметр ``1指定调用该方法的**对象**,参数
2` — это значение списка параметров метода.
Если вызываемый методстатический метод, параметр 1 нужно передать только вnull
, потому что статические методы не относятся к объекту, а только к классу.
Вы можете создать экземпляр объекта через отражение следующим образом, а затем получитьMethod
объект метода, вызовinvoke()
уточнитьSmallPineapple
изgetInfo()
метод.
Class clazz = Class.forName("com.bean.SmallPineapple");
Constructor constructor = clazz.getConstructor(String.class, int.class);
constructor.setAccessible(true);
SmallPineapple sp = (SmallPineapple) constructor.newInstance("小菠萝", 21);
Method method = clazz.getMethod("getInfo");
if (method != null) {
method.invoke(sp, null);
}
// [小菠萝的年龄是:21]
Сценарии применения рефлексии
Общие сценарии применения рефлексии представлены здесь.3
Кусок:
- Объекты, созданные Spring: при запуске программы Spring прочитает файл конфигурации.
applicationContext.xml
И проанализируйте все теги внутри, созданные дляIOC
в контейнере. - отражение + заводской узор: проход
反射
Устраните несколько ветвей в фабрике.Если вам нужно создать новые классы, вам не нужно обращать внимание на фабричный класс.Фабричный класс может иметь дело с различными новыми классами.反射
Можно сделать программу более надежной. - Соединение JDBC с базой данных: при использовании JDBC для соединения с базой данных укажите
驱动类
При использовании отражения для загрузки классов драйверов
Контейнер Spring IOC
В Spring файл конфигурации контекста часто пишетсяapplicationContext.xml
, что примерноbean
конфигурации, когда программа запустится, она прочитает файл xml и проанализирует все<bean>
пометить и создать экземпляр объекта вIOC
в контейнере.
<?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">
<bean id="smallpineapple" class="com.bean.SmallPineapple">
<constructor-arg type="java.lang.String" value="小菠萝"/>
<constructor-arg type="int" value="21"/>
</bean>
</beans>
После определения указанного выше файла перейдитеClassPathXmlApplicationContext
Загрузите файл конфигурации, когда программа запустится, Springbean
Все экземпляры создаются и помещаются в контейнер IOC.Контейнер IOC, по сути, является фабрикой, через которую передаются теги id
свойство, чтобы получить соответствующий экземпляр.
public class Main {
public static void main(String[] args) {
ApplicationContext ac =
new ClassPathXmlApplicationContext("applicationContext.xml");
SmallPineapple smallPineapple = (SmallPineapple) ac.getBean("smallpineapple");
smallPineapple.getInfo(); // [小菠萝的年龄是:21]
}
}
После того, как Spring упростил процесс создания экземпляров объектов, его можно понимать как этапы создания экземпляров объектов путем отражения:
- Получить конструктор объекта класса
- по конструкторувызвать новый экземпляр ()созданный объект
Конечно, Spring выполняет множество дополнительных операций при создании экземпляров объектов, так что текущей разработки может быть достаточно.Удобный и стабильный.
В следующей статье я напишу статью, в которой объясню, как использовать отражение для реализации
简易版
изIOC
Контейнер, принцип контейнера IOC очень прост. Пока вы овладеваете идеей отражения и понимаете общий API отражения, вы можете реализовать его. Я могу предложить простую идею: используйте HashMap для хранения всех экземпляров, и ключ представляет собой значение тега. id
значение хранит соответствующий экземпляр, который по умолчанию соответствует объекту, управляемому контейнером IOC Spring.синглтониз.
Отражение + абстрактный заводской узор
Традиционный фабричный шаблон, если необходимо создать новый подкласс,Необходимо изменить фабричный класс и добавить новую ветку в фабричный класс.;
public class MapFactory {
public Map<Object, object> produceMap(String name) {
if ("HashMap".equals(name)) {
return new HashMap<>();
} else if ("TreeMap".equals(name)) {
return new TreeMap<>();
} // ···
}
}
Используя комбинацию шаблонов отражения и фабрики при создании новых подклассов,Фабричный класс не нужно ничего модифицировать, можно сосредоточиться на реализации подкласса,Когда подкласс определен, фабрика также может производить подкласс.
отражение + абстрактная фабрикасмыслДа:
- Во время выполнения полные имена разных подклассов передаются в качестве параметров для получения разных объектов класса, а метод newInstance() вызывается для возврата разных подклассов.Внимательный читатель обнаружит, что упомянутоеПодклассЭта концепция, то есть отражение + абстрактный фабричный шаблон, обычно используется длянаследоватьилиреализация интерфейсасвязь.
Например, какой из них использовать, определяется во время выполнения.Map
структуру, мы можем использовать отражение, чтобы передать полное имя конкретной Карты для создания экземпляра определенного подкласса.
public class MapFactory {
/**
* @param className 类的全限定名
*/
public Map<Object, Object> produceMap(String className) {
Class clazz = Class.forName(className);
Map<Object, Object> map = clazz.newInstance();
return map;
}
}
className
Его можно указать как java.util.HashMap или java.util.TreeMap и т. д., в зависимости от бизнес-сценария.
Класс драйвера загрузки базы данных JDBC
При импорте сторонних библиотек JVM не будет активно загружать импортированные извне классы, ноПодождите, пока он действительно не будет использован, прежде чем загружать необходимые классы., вот и все, мы можем передать полное имя класса драйвера, когда получим соединение с базой данных, и позволить JVM загрузить класс.
public class DBConnectionUtil {
/** 指定数据库的驱动类 */
private static final String DRIVER_CLASS_NAME = "com.mysql.jdbc.Driver";
public static Connection getConnection() {
Connection conn = null;
// 加载驱动类
Class.forName(DRIVER_CLASS_NAME);
// 获取数据库连接对象
conn = DriverManager.getConnection("jdbc:mysql://···", "root", "root");
return conn;
}
}
Когда мы разрабатываем SpringBoot-проекты, мы будем часто сталкиваться с этим классом, но он может стать естественным, и мне все равно, я покажу вам самые распространенные здесь.application.yml
Конфигурация базы данных в , я думаю, вы должны это внезапно осознать.
здесьdriver-class-name, похож ли он на класс, который мы загрузили в начале? Это потому, чтоMySQLвызвано разными версиямиразные водители, что отражает преимущества использования отражения: нет необходимости изменять исходный код,Замена класса драйвера может быть завершена только загрузкой конфигурационного файла.
В следующих статьях я напишу статью, чтобы подробно представить сценарии применения отражения и реализовать простые
IOC
Контейнеры и преимущества реализации фабричного шаблона через отражение.Здесь вам нужно только освоить базовое использование рефлексии и ее идей, а также понять основные сценарии ее использования.
Преимущества и недостатки отражения
Отраженныйпреимущество:
- Повышение гибкости программы: Гибкость создания экземпляров различных объектов перед лицом меняющихся требований.
Однако есть и выигрыши и проигрыши.Технология не может иметь одних достоинств и не иметь недостатков, и рефлексия тоже имеетЕще два непонятных недостатка:
- Уничтожить инкапсуляцию класса: Может обеспечить доступ к частной оформленной информации.
- потеря производительности: По сравнению с непосредственным созданием экземпляров объектов, вызовом методов и доступом к переменным, отражение требует много усилий.Шаги проверки и шаги синтаксического анализа, JVM не может их оптимизировать.
Повышение гибкости программы
Вместо того, чтобы использовать в качестве примера SmallPineapple, давайте рассмотрим более贴近开发
пример:
- Используйте отражение для подключения к базе данных,Источники данных, связанные с базой данных. В SpringBoot все соглашения больше, чем конфигурация, хотитепользовательская конфигурациякогда используешь
application.properties
Файл конфигурации указывает источник данных
Персона 1 - Дизайнер Java: мы разработалиDataSource
интерфейс, другие поставщики баз данных хотят, чтобы разработчики использовали你们的数据源
Чтобы контролировать базу данных, вы должны понимать我的这个接口
!
Роль 2 — Поставщик базы данных:
- Поставщики баз данных MySQL: мы предоставляемcom.mysql.cj.jdbc.MysqlDataSourceИсточник данных, который разработчики могут использовать для подключения к MySQL.
- Поставщики Alibaba: мы предоставилиcom.alibaba.druid.pool.DruidDataSourceИсточник данных, мой источник данных более мощный, смониторинг страниц,Медленное ведение журнала SQLИ другие функции, разработчики приходят и используют его для мониторинга MySQL!
- Поставщики SQLServer: мы предоставляемcom.microsoft.sqlserver.jdbc.SQLServerDataSourceИсточник данных, если вы хотите использовать SQL Server в качестве базы данных, используйте наше подключение к источнику данных.
Персона 3 — Разработчик: мы можем использовать配置文件
указанное использованиеDruidDataSource
источник данных
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
Изменение требований: Однажды к нам пришел босс и сказал, что источник данных Druid не подходит для нашего текущего проекта, мы используемMysqlDataSourceЧто ж, тогда программист изменит файл конфигурации, перезагрузит файл конфигурации и перезапустит проект, чтобы завершить переключение источника данных.
spring.datasource.type=com.mysql.cj.jdbc.MysqlDataSource
При изменении источника данных, подключающегося к базе данных, вам нужно только изменить файл конфигурации.Нет необходимости менять какой-либо код, Причина в том, что:
- Нижний уровень Spring Boot инкапсулирует конфигурацию источника данных для подключения к базе данных и использует отражение для адаптации к каждому источнику данных.
Ниже приведен краткий анализ исходного кода. мы используемctrl+左键
нажмитеspring.datasource.type
Войдите в класс DataSourceProperties и обнаружите, что использование setType()Преобразование полного имени класса в объект классавводить вtype
в переменных-членах. При подключении и мониторинге базы данных используется указанная операция источника данных.
private Class<? extends DataSource> type;
public void setType(Class<? extends DataSource> type) {
this.type = type;
}
Class
объект определяет общую верхнюю границуDataSource
, давайте взглянем на основные источники данных类图结构
.
На приведенном выше рисунке показаны некоторые источники данных, конечно, их больше, но мы видим, что независимо от того, какой источник данных указан, нам нужно иметь дело только с файлом конфигурации без изменения исходного кода, что является гибкостью отражения. !
Уничтожить инкапсуляцию класса
Очевидная особенность, отражение может получитьprivate
Модифицированные переменные, методы и конструкторы, которыеНарушает объектно-ориентированную инкапсуляцию, потому что изменение с помощью private означает, что вы не хотите раскрывать его внешнему миру и разрешаете доступ только этому классу, иsetAccessable(true)
Модификаторы доступа можно игнорировать, и внешний мир может обеспечить доступ.
все еще помню单例模式
Текст? В нем говорится о том, что отражение уничтожает голодные и ленивые одноэлементные шаблоны, поэтому я использовал его позже.枚举
Избегайте отражения нокаутом.
Возвращаясь к исходной отправной точке, в SmallPineapple есть атрибут веса, который модифицируется модификатором private, цель которого состоит в том, чтобы вы не хотели, чтобы ваш вес был известен внешнему миру.
public class SmallPineapple {
public String name;
public int age;
private double weight; // 体重只有自己知道
public SmallPineapple(String name, int age, double weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
}
Хотя атрибут веса теоретически известен только ему самому, если он отражен, то этот класс как вполосыто же, становится перед лицом отражения一览无遗
.
SmallPineapple sp = new SmallPineapple("小菠萝", 21, "54.5");
Clazz clazz = Class.forName(sp.getClass());
Field weight = clazz.getDeclaredField("weight");
weight.setAccessable(true);
System.out.println("窥觑到小菠萝的体重是:" + weight.get(sp));
// 窥觑到小菠萝的体重是:54.5 kg
потеря производительности
Когда вы напрямую создаете новый объект и вызываете методы объекта и свойства доступа, компилятор заранее проверяет доступность во время компиляции.Если вы попытаетесь получить неправильный доступ, IDE заранее выдаст сообщение об ошибке, например несоответствие типа передачи параметров, незаконный доступ к закрытым свойствам и методам.
При использовании отражения для управления объектами компилятор не может заранее знать тип объекта, является ли доступ допустимым и соответствует ли тип передачи параметров. Только когда отраженный код вызывается во время работы программы, она проверяет, вызывает и возвращает результат с нуля, и JVM не может оптимизировать отраженный код.
Хотя отражение имеет характеристики потери производительности, мы не можем обобщать его, и мысль о том, что использование отражения ухудшит производительность, отражение работает медленно, и его нужно вызывать одновременно.100W
Оно может проявляться только после нескольких или десятков обращений, что не отражает низкой эффективности рефлексии. Так что не носите вслепую затемненные очки, чтобы увидеть отражения,Во время одного вызова рефлексии снижение производительности незначительно. Если требования к производительности программы очень высоки, то старайтесь не использовать рефлексию.
Основы рефлексии Конец статьи Резюме
- Отраженные мысли: Отражения подобнызеркалото же, вВремя выполненияТолько когда вы видите, кто вы есть, вы можете получить свою собственную информацию и даже создавать экземпляры объектов.
- Роль отражения:Объект создается во время выполнения, что делает программу более надежной., Перед лицом изменений в требованиях можно свести к минимуму модификацию исходного кода программы для работы с различными сценариями и создания экземпляров различных типов объектов.
- Общие сценарии применения рефлексии:
3
Первый: контейнер IOC Spring, режим отражения + фабрика делает класс фабрики более стабильным и загружает класс драйвера, когда JDBC подключается к базе данных. - Отраженный
3
Особенности: Повышение гибкости программы, разрушение инкапсуляции классов и снижение производительности.
Привет, я cxuan, я написал четыре PDF-файла самостоятельно, а именно: Сводка основ Java, Сводка ядра HTTP, Основы компьютера, Сводка ядра операционной системы, я организовал их в PDF-файлы, вы можете подписаться на официальную учетную запись Java Builder, чтобы ответить на PDF для получения информации о качестве.