1. Что такое отражение
1. Начальный рефлекс
Когда я впервые научился размышлять, я был сбит с толку, эта штука действительно"абстрактная мама открывает дверь в абстрактное - абстрактное дома. "
Почему вам нужно сначала получить объект класса, чтобы создать объект? Разве это не много работы? Не было бы проще, если бы я просто новый?
чтоПолучить свойства и методы класса во время работы программы? Обычно программа компилируется неправильно, а потом модифицируется код, почему я должен учитывать состояние программы во время ее работы?
Я обычно не использую его для разработки, какой смысл изучать этот материал?
Позже, узнав об аннотациях, spring, SpringMVC и других технологиях, я обнаружил, что отражение есть везде.
2. JVM загружает классы
Программу Java, которую мы пишем, нужно запускать в JVM, поэтому, чтобы изучить отражение, нам сначала нужно понять процесс загрузки классов JVM.
1. Файлы .java, которые мы пишем, называются исходным кодом.
2. Мы пишем основной метод в классе, а затем нажимаем кнопку запуска IDEA.Когда JVM запускается, она запускает команду javac jdk для компиляции исходного кода в файл .class, который также называется байт-кодом. файл.
3. JVMзагрузчик классов(можно понимать как инструмент) через классполное имячтобы получить поток двоичных байтов класса, а затем загрузить файл класса в область методов JVM.
4. Когда загрузчик классов загружает файл .class в область методов, онв кучеСоздает уникальный объект Class, содержащий переменные-члены, конструкторы и методы-члены этого класса.
5. Этот объект класса создаст экземпляр объекта, соответствующий классу.
Таким образом, на первый взгляд вы создаете новый объект, но на самом деле, когда JVM запускает программу, то, что действительно помогает вам создать объект, — это объект Class класса.
Другими словами, отражение на самом деле заключается в том, что JVM инкапсулирует все классы, которые вы создаете, в уникальный объект Class при запуске программы. Этот объект Class содержит свойства, конструкторы и методы-члены. Получив объект класса, вы также можете получить эти три вещи.
После получения атрибутов отражения (класса) вы можете получить имя атрибута, тип атрибута, значение атрибута объекта, а также установить значение атрибута.
После того, как вы получите конструктор после отражения (класса), вы можете создавать объекты.
После того, как вы получите метод отражения члена (класс), вы можете выполнить этот метод.
3. Концепция отражения
Механизм отражения JAVA находится вПрограмма работаетВ состоянии для любого класса можно знать все свойства и методы этого класса, для любого объекта можно вызывать любые его методы и свойства, эта функция динамического получения информации и динамического вызова методов объекта называется языком java. механизм отражения.
Зная процесс загрузки классов JVM, я считаю, что у вас должно быть более глубокое понимание концепции отражения.
отражение: JVM runner --> файл .java --> файл .class --> объект класса --> создать экземпляр объекта и управлять свойствами и методами экземпляра.
Далее я расскажу о связанных классах и общих методах отражения.
2. Объект класса
Получить объект класса
Сначала создайте класс пользователя:
public class User {
private String name = "知否君";
public String sex = "男";
public User() {
}
public User(String name, String sex) {
this.name = name;
this.sex = sex;
}
public void eat(){
System.out.println("人要吃饭!");
}
private void run(){
System.out.println("人要跑步!");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
}
Есть три способа получить объект класса:
1. Class.forName("полное имя класса")
Полное имя класса: имя пакета + имя класса
Class userClass = Class.forName("com.xxl.model.User");
2. имя класса.класс
Class userClass = User.class;
3. Объект.получитькласс()
User user = new User();
Class userClass = user.getClass();
Хотя есть три способа получить объект класса, мы обычно используем первый метод, описанный выше.
Получив объект класса, мы можем управлять связанными с ним методами.
3. Получите имя класса
1. Получите полное имя класса: имя пакета + имя класса
getName()
Class userClass = Class.forName("com.xxl.model.User");
String name = userClass.getName();
System.out.println(name);
распечатать результат:
2. Получить простое имя класса: исключая имя пакета
getSimpleName()
Class userClass = Class.forName("com.xxl.model.User");
String simpleName = userClass.getSimpleName();
System.out.println(simpleName);
распечатать результат:
4. Свойства
4.1 Получить свойства
1. Получить всепубличныйАтрибут: публичная модификация
getFields()
Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
распечатать результат:
2. Получите единую общедоступную собственность
getField("имя свойства")
Class userClass = Class.forName("com.xxl.model.User");
Field field = userClass.getField("sex");
System.out.println(field);
распечатать результат:
3. Получить все свойства: общедоступные + частные
getDeclaredFields()
Class userClass = Class.forName("com.xxl.model.User");
Field[] fields = userClass.getDeclaredFields();
for (Field field : fields) {
System.out.println(field);
}
распечатать результат:
4. Получите одно свойство: публичное или приватное
getDeclaredField("имя свойства")
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
Field sexField = userClass.getDeclaredField("sex");
System.out.println(nameField);
System.out.println(sexField);
распечатать результат:
4.2 Эксплуатационные свойства
1. ПолучитьИмя свойства
getName()
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getName());
распечатать результат:
2. Получитьтип недвижимости
getType()
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
System.out.println(nameField.getType());
распечатать результат:
3. Получитьзначение атрибута
get(object)
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("sex");
User user = new User();
System.out.println(nameField.get(user));
распечатать результат:
Примечание:Значение частного свойства нельзя получить напрямую посредством отражения, но значение частного свойства можно получить, изменив запись доступа.
Установите, чтобы разрешить доступ к частным свойствам:
field.setAccessible(true);
Например:
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
System.out.println(nameField.get(user));
Метод печати:
4. Установите значение свойства
установить (объект, «значение атрибута»)
Class userClass = Class.forName("com.xxl.model.User");
Field nameField = userClass.getDeclaredField("name");
nameField.setAccessible(true);
User user = new User();
nameField.set(user,"张无忌");
System.out.println(nameField.get(user));
распечатать результат:
5. Конструктор
1. Получить все общедоступные конструкторы
getConstructors()
Class userClass = Class.forName("com.xxl.model.User");
Constructor[] constructors = userClass.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
распечатать результат:
2. Получите конструктор, соответствующий типу параметра
getConstructor (тип параметра)
Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
System.out.println(constructor);
распечатать результат:
6. Методы-члены
6.1 Метод получения члена
1. Получить все общедоступные методы
getMethods()
Class userClass = Class.forName("com.xxl.model.User");
Method[] methods = userClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
распечатать результат:
Мы обнаружили, что в дополнение к пользовательским общедоступным методам в результатах печати есть общедоступные методы, унаследованные от класса Object.
2. Получите общедоступный метод
getMethod("имя метода", тип параметра)
Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getMethod("setName", String.class);
System.out.println(method);
распечатать результат:
3. Получить все методы: публичные + приватные
getDeclaredMethods()
Class userClass = Class.forName("com.xxl.model.User");
Method[] declaredMethods = userClass.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method);
}
распечатать результат:
4. Получить метод: публичный или приватный
getDeclaredMethod("имя метода", тип параметра)
Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("run");
System.out.println(method);
распечатать результат:
6.2 Реализация методов-членов
вызывать(объект, "параметры метода")
Class userClass = Class.forName("com.xxl.model.User");
Method method = userClass.getDeclaredMethod("eat");
User user = new User();
method.invoke(user);
распечатать результат:
Примечание:Частные методы-члены не могут выполняться напрямую через отражение, но могут быть настроены на разрешение доступа.
Установите, чтобы разрешить выполнение приватных методов:
method.setAccessible(true);
7. Примечания
1. Определите, когда класс или метод содержит аннотацию
isAnnotationPresent(注解名.class)
Например:
Class userClass = Class.forName("com.xxl.model.User");
if(userClass.isAnnotationPresent(Component.class)){
Component annotation = (Component)userClass.getAnnotation(Component.class);
String value = annotation.value();
System.out.println(value);
};
2. Получите аннотации
getAnnotation(注解名.class)
Например:
Class userClass = Class.forName("com.xxl.model.User");
// 获取类上的注解
Annotation annotation1 = userClass.getAnnotation(Component.class);
Method method = userClass.getMethod("eat");
// 获取方法上的某个注解
Annotation annotation2 = userClass.getAnnotation(Component.class);
8. Создайте экземпляр класса
1. Создание объектов через класс
Class.newInstance()
Class userClass = Class.forName("com.xxl.model.User");
User user = (User)userClass.newInstance();
System.out.println("姓名:"+user.getName()+" 性别:"+user.getSex());
распечатать результат:
2. Создайте экземпляр объекта через конструктор
конструктор.newInstance (значение параметра)
Class userClass = Class.forName("com.xxl.model.User");
Constructor constructor = userClass.getConstructor(String.class, String.class);
User user = (User)constructor.newInstance\("李诗情", "女"\);
System.out.println("姓名:"+user.getName()+" 性别:"+user.getSex());
распечатать результат:
9. Случай отражения
Однажды технический директор сказал Чжан Саню: «Чжан Сан, я слышал, что вы недавно изучили рефлексию. Тогда вы можете создать фабричный класс для объекта и показать его мне».
Чжан Сан подумал про себя: «Эй, уже почти канун Нового года, босс собирается дать мне повышение. На этот раз я сделаю все возможное».
Через 5 минут Чжан Сан отправил код:
public class ObjectFactory {
public static User getUser() {
User user = null;
try {
Class userClass = Class.forName("com.xxl.model.User");
user = (User) userClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return user;
}
public static UserService getUserService() {
UserService userService = null;
try {
Class userClass = Class.forName("com.xxl.service.impl.UserServiceImpl");
userService = (UserService) userClass.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
return userService;
}
}
Технический директор взглянул на код и сказал Чжан Саню: «С вашим заводским классом есть две проблемы».
1. В коде много избыточности. Если у вас есть 10 000 классов, вы хотите написать 10 000 статических методов?
2. Связывание кода слишком сильное. Если изменится путь к пакету, в котором хранятся эти классы, возникнут ли проблемы при использовании forName() для получения объекта Class? Вы также должны вручную изменить код один за другим, а затем скомпилировать, упаковать и развернуть. . Вы не находите это хлопотным?
«Рассеивайте свои мысли и подумайте, можете ли вы просто спроектировать статический класс и создать объект путем отражения путем передачи параметров. Передаваемые параметры должны уменьшить связь с фабричным классом. Кстати, вы можете обратиться к JDBC для получения соединений с базой данных. . параметры."
Чжан Саньи выслушал: «Как и ожидалось от режиссера, вы такой сильный! Подождите меня 10 минут».
Через 10 минут Чжан Сан снова отправил код:
object.properties
user=com.xxl.model.User
userService=com.xxl.service.impl.UserServiceImpl
ObjectFactory
public class ObjectFactory {
private static Properties objectProperty = new Properties();
// 静态方法在类初始化时执行,且只执行一次
static{
try {
InputStream inputStream = ObjectFactory.class.getResourceAsStream("/object.properties");
objectProperty.load(inputStream);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public static Object getObject(String key){
Object object = null;
try {
Class objectClass = Class.forName(objectProperty.getProperty(key));
object = objectClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
return object;
}
}
Методы испытаний:
@Test
void testObject() {
User user = (User)ObjectFactory.getObject("user");
UserService userService = (UserService)ObjectFactory.getObject("userService");
System.out.println(user);
System.out.println(userService);
}
Результаты:
Директор кивнул и с улыбкой сказал Чжан Саню: «Использование файла свойств для хранения полного имени класса снижает степень связанности кода, а использование отражения для создания объектов путем передачи параметров уменьшает избыточность кода. Его можно изменить».
«Окей, сегодня вечером проект запустят, давайте сначала поедим, а потом исправим баг».
Чжан Сан: «...Хороший режиссер».
10. Роль отражения
Мы более или менее слышали, что отражение используется при разработке фреймворков, таких как Spring IOC. Шаблон фабрики и отражение используются для создания объектов, а нижний слой BeanUtils также использует отражение для копирования свойств. Так что отражения повсюду.
Хотя мы почти не используем отражение в нашей повседневной разработке, мы должны понимать принцип отражения, потому что это может помочь нам понять принцип проектирования фреймворка.