Программа, способная анализировать возможности класса, называется рефлексивной.. Механизм отражения очень мощный и в основном обеспечивает следующие функции:
-
Для любого класса вы можете знать все свойства и методы этого класса;
-
Для любого объекта может быть вызван любой его метод и свойство;
Сорт
Во время выполнения программы исполняющая система Java всегда поддерживает для всех объектов идентификатор типа, называемый исполняющей средой. Эта информация отслеживает класс, к которому принадлежит каждый объект. Виртуальная машина использует информацию о типе среды выполнения, чтобы выбрать соответствующий метод для выполнения. Однако,Доступ к этой информации можно получить через специальный класс Java с именем java.lang.Class..
Экземпляры класса Class представляют классы и интерфейсы в запущенном Java-приложении. Перечисление — это класс, аннотация — это интерфейс. Каждый массив также принадлежит классу, который отражается как объект Class, общий для всех массивов с одинаковым типом элемента и размером. Примитивные типы Java (boolean, byte, char, short, int, long, float и double) и ключевое слово void также представлены как объекты класса.
Класс класса не имеет открытого конструктора. Объекты класса автоматически создаются виртуальной машиной Java при загрузке класса и вызове метода defineClass в загрузчике классов.
Хотя мы не можем создать новый объект класса, мы можем получить объект класса через существующий класс тремя способами:
1. Метод forName класса Class
Class<?> clazz = Class.forName("com.codersm.study.jdk.reflect.Person");
2. Через метод getClass() объекта класса
Class<?> clazz = new Person().getClass();
3. Литеральная константа класса
Class<Person> clazz = Person.Class;
резюме:
Обратите внимание, что при вызове метода forName необходимо перехватывать исключение с именем ClassNotFoundException, так как метод forName не может определить, существует ли в методе forName класс, соответствующий переданной строке, его можно проверить только во время работы программы. Исключение ClassNotFoundException.
Литералы классов проще и безопаснее. Потому что это будет проверяться компилятором и будет эффективнее, потому что нет необходимости вызывать метод forName,Поскольку получение ссылки на объект класса через литеральный метод не инициализирует автоматически класс?.Еще интереснее то, что способ получения ссылки на объект класса через литеральные константы можно применять не только к обычным классам, но и к интерфейсам, массивам и базовым типам данных.
Класс Class предоставляет большое количество методов экземпляра для получения подробной информации, соответствующей объекту Class. Класс Class примерно включает следующие методы, каждый из которых содержит несколько перегруженных версий, поэтому мы делаем только краткое введение. Подробности см. Ссылаться надокументация JDK.
-
Получить информацию о классе
получить контент сигнатура метода Конструктор Constructor<T> getConstructor(Class<?>... parameterTypes)
метод Method getMethod(String name, Class<?>... parameterTypes)
Атрибуты Field getField(String name)
Annotation <A extends Annotation> A getAnnotation(Class<A> annotationClass)
внутренний класс Class<?>[] getDeclaredClasses()
внешний класс Class<?> getDeclaringClass()
Реализованный интерфейс Class<?>[] getInterfaces()
модификатор int getModifiers()
в упаковке Package getPackage()
имя класса String getName()
короткое имя String getSimpleName()
Примечание: метод getDeclaredXxx может получить все Xxx, независимо от того, частные они или общедоступные.
-
Как судить об информации самого класса
Судя по содержанию сигнатура метода Тип аннотации? boolean isAnnotation()
Этот модификатор аннотации используется? boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
Анонимный класс? boolean isAnonymousClass()
множество? boolean isArray()
перечислить? boolean isEnum()
примитивный тип? boolean isPrimitive()
интерфейс? boolean isInterface()
Является ли obj экземпляром этого класса boolean isInstance(Object obj)
-
Создание пар и управление ими с помощью отражения
-
Программа может выполнить соответствующий метод через объект Method;
-
Вызовите соответствующий конструктор для создания экземпляра через объект Constructor;
-
Прямой доступ и изменение значения переменной-члена объекта через объект Filed.
-
создать объект
Есть два способа генерировать объекты посредством отражения:
-
Используйте метод newInstance() объекта Class для создания экземпляра соответствующего класса объекта Class (этот метод требует, чтобы соответствующий класс объекта Class имел конструктор по умолчанию).
-
Сначала используйте объект Class, чтобы получить указанный объект Constructor, а затем вызовите метод newInstance() объекта Constructor, чтобы создать экземпляр соответствующего класса объекта Class (таким образом, указанный конструктор может быть выбран для создания пример).
class Person {
private String name;
private Integer age;
public Person() {
this.name = "system";
this.age = 99;
}
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
public Integer getAge() {
return age;
}
public String getName() {
return name;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<Person> pClass = Person.class;
// 通过第1种方式创建对象
Person p = pClass.newInstance();
System.out.println(p);
// 通过第2种方式创建对象
Constructor<Person> constructor = pClass.getDeclaredConstructor(
String.class, Integer.class);
Person person2 = constructor.newInstance("zhangsan",20);
System.out.println(person2);
}
}
метод вызова
После получения объекта класса, соответствующего классу, вы можете получить массив методов или объект метода с помощью метода getMethod объекта класса. Каждый объект метода соответствует методу. После получения объекта метода вы можете вызвать метод вызова, чтобы получить Вызовите метод, соответствующий объекту Method.
Person person = new Person();
// 获取getAge方法
Method getAgeMethod = person.getClass().getMethod("getAge",null);
// 调用invoke方法来调用getAge方法
Integer age = (Integer) getAgeMethod.invoke(person,null);
System.out.println(age);
доступ к переменным-членам
Все или указанные переменные-члены Field, содержащиеся в классе, можно получить с помощью метода getField() объекта Class.Field предоставляет следующие две группы методов для чтения и установки значений переменных-членов.
-
getXxx (Object obj): получить значение переменной-члена объекта obj, где Xxx соответствует 8 основным типам, если тип переменной-члена является ссылочным типом, отменить Xxx после получения;
-
setXxx(Object obj, Xxx val): Установите значение переменной-члена объекта obj в значение val. Xxx здесь соответствует 8 базовым типам. Если тип члена является ссылочным типом, отмените Xxx после набора;
Person person = new Person();
// 获取name成员变量Field
Field nameField = person.getClass().getDeclaredField("name");
// 启用访问控制权限
nameField.setAccessible(true);
// 获取person对象的成员变量name的值
String name = (String) nameField.get(person);
System.out.println("name = " + name);
// 设置person对象的成员变量name的值
nameField.set(person, "lisi");
System.out.println(person);
Управление массивами
В пакете Java java.lang.reflect есть класс, который может динамически манипулировать массивами Array предоставляет методы для динамического создания массивов Java и доступа к ним. Массивы позволяют получить доступ к значениям и присвоить их при выполнении операций получения или установки. Методы, связанные с массивами в классе Class:
метод | иллюстрировать |
---|---|
public native Class<?> getComponentType() | Возвращает класс, представляющий тип элемента массива, т.е. тип массива |
public native boolean isArray() | Определяет, представляет ли этот объект Class класс массива |
Общие статические методы в java.lang.reflect.Array следующие:
-
newInstance(Class<?> componentType, int length)
-
newInstance(Class<?> componentType, int... dimensions)
-
int getLength(Object array)
-
Object get(Object array, int index)
-
void set(Object array, int index, Object value)
Для реализации общей функции копирования массива код выглядит следующим образом:
public class GenericityArray {
public static <T> T[] copy(T[] clazz) {
return (T[]) Array.newInstance(
clazz.getClass().getComponentType(),
clazz.length);
}
public static void main(String[] args) {
Integer[] array = {1, 2, 3};
Integer[] copyArray = GenericityArray.copy(array);
System.out.println(copyArray.length);
}
}
Получите общую информацию, используя отражение
Чтобы управлять дженериками посредством отражения для удовлетворения потребностей фактической разработки, в Java добавленыjava.lang.reflect.ParameterizedType
,java.lang.reflect.GenericArrayType
,java.lang.reflect.TypeVariable
,java.lang.reflect.WildcardType
.
Типы | имея в виду |
---|---|
ParameterizedType | Параметризованный тип, например Collection |
GenericArrayType | Тип элемента — это параметризованный тип или тип массива переменной типа. |
TypeVariable | публичный интерфейс для различных типов переменных |
WildcardType | Выражение типа подстановочного знака, например ?, расширяет число. |
Среди них мы можем использовать ParameterizedType для получения общей информации.
public class Client {
private Map<String, Object> objectMap;
public void test(Map<String, User> map, String string) {
}
public Map<User, Bean> test() {
return null;
}
/**
* 测试属性类型
*
* @throws NoSuchFieldException
*/
@Test
public void testFieldType() throws NoSuchFieldException {
Field field = Client.class.getDeclaredField("objectMap");
Type gType = field.getGenericType();
// 打印type与generic type的区别
System.out.println(field.getType());
System.out.println(gType);
System.out.println("**************");
if (gType instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) gType;
Type[] types = pType.getActualTypeArguments();
for (Type type : types) {
System.out.println(type.toString());
}
}
}
/**
* 测试参数类型
*
* @throws NoSuchMethodException
*/
@Test
public void testParamType() throws NoSuchMethodException {
Method testMethod = Client.class.getMethod("test", Map.class, String.class);
Type[] parameterTypes = testMethod.getGenericParameterTypes();
for (Type type : parameterTypes) {
System.out.println("type -> " + type);
if (type instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) type).getActualTypeArguments();
for (Type actualType : actualTypes) {
System.out.println("\tactual type -> " + actualType);
}
}
}
}
/**
* 测试返回值类型
*
* @throws NoSuchMethodException
*/
@Test
public void testReturnType() throws NoSuchMethodException {
Method testMethod = Client.class.getMethod("test");
Type returnType = testMethod.getGenericReturnType();
System.out.println("return type -> " + returnType);
if (returnType instanceof ParameterizedType) {
Type[] actualTypes = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type actualType : actualTypes) {
System.out.println("\tactual type -> " + actualType);
}
}
}
}
Получение аннотаций с помощью отражения
Введение в использование отражения для получения аннотационной информации см.Практика написания аннотаций в Java