Рефлексия представляет мощный механизм, который позволяет динамически во время выполнения анализировать возможности классов и исследовать их и их функционал. Рефлексия может быть полезна при создании различных плагинов, анализаторов и других типов приложений, когда динамически надо получать информацию о программе, ее типах данных и при возможности даже взаимодействовать с ними, даже если эти типы данных определяли не вы, и их код вам не доступен.
Ключевым классом для исследования типов является класс Class в языке Java. Рассмотрим его основные методы:
Field[] getFields(): возвращает массив объектов Field для открытых полей данного класса или его суперклассов. Метод возвращают массив нулевой длины, если таких полей нет или если объект
представляет собой примитивный тип или массив
Field[] getDeclaredFields(): возвращает массив объектов Field для всех полей данного класса. Метод возвращают массив нулевой длины, если таких полей нет или если объект
представляет собой примитивный тип или массив.
Method[] getMethods(): возвращает открытые методы в виде объектов Method (в том числе и унаследованные методы)
Method[] getDeclaredMethods(): возвращает все методы данного класса или интерфейса, но не включает унаследованные методы
Constructor[] getConstructors(): возвращает массив объектов Constructor, которые представляют все открытые конструкторы
Constructor[] getDeclaredConstructors(): возвращает массив объектов Constructor, которые представляют все конструкторы, определенные непосредственно в этом классе
boolean isAnonymousClass(): возвращает true, если тип является анонимным классом
boolean isArray(): возвращает true, если тип представляет массив
boolean isPrimitive(): возвращает true, если тип является примитивным типом
boolean isInterface(): возвращает true, если объект представляет интерфейс
boolean isEnum(): возвращает true, если объект представляет перечисление
boolean isRecord(): возвращает true, если объект представляет класс record
boolean isInstance(Object obj): возвращает true, если объект-параметр является экземпляром этого типа
boolean isSealed(): возвращает true, если класс определен с модификатором sealed
Class getSuperclass(): возвращает суперкласс для текущего типа
RecordComponent[] getRecordComponents(): возвращает массив объектов RecordComponent, которые описывают поля объекта, или null, если этот объект не представляет класс record.
String getPackageName(): получает имя пакета, содержащего этот тип, или пакета типа элемента, если этот тип является массивом, или "java.lang", если этот тип является примитивным типом.
Чтобы исследовать типы, нам прежде всего надо получить соответствуюзий типу объект Class. Для этого есть три способа:
Метод getClass() в классе Object (а, значит, и у всех остальных классов) возвращает экземпляр типа Class
Статический метод Class.forName() принимает полное (квалифицированное) имя типа с учетом пакетов и
возвращает объект Class, который представляет этот тип
Поле class в классе Object (а, значит, и у всех остальных классов) возвращает экземпляр типа Class
Самый простой способ получить связанный с типом объект Class - это метод getClass(), который есть у всех типов в языке Java:
public class Program{
public static void main(String[] args) {
Person tom = new Person();
Class personClass = tom.getClass();
System.out.println(personClass); // class Person
}
}
class Person{ }
Здесь получаем информацию о классе Person, а консоль выведет нам строку "class Person", что вообщем-то очевидно.
Если тип расположен в другом пакете, то выводится полное (квалифицированное) имя класса с учетом пакетов. Например:
public class Program{
public static void main(String[] args) {
String text = "";
System.out.println(text.getClass()); // class java.lang.String
}
}
Так, для строки (объекта String) полное имя класса будет "java.lang.String"
Cтатическоий метод Class.forName() принимает полное (квалифицированное) имя типа с учетом пакетов и
возвращает объект Class, который представляет этот тип:
public class Program{
public static void main(String[] args) {
try{
Class personClass = Class.forName("Person");
System.out.println(personClass); // class Person
Class strClass = Class.forName("java.lang.String");
System.out.println(strClass); // class java.lang.String
}
catch(ClassNotFoundException ex){
System.out.println("Class not found");
}
}
}
class Person{ }
При использовании этого метода стоит учитывать, что если Java не найдет класс по переданному имени, то будет сгенерировано исключение ClassNotFoundException, поэтому на уровне кода надо обрабатывать это исключение.
Cтатическое поле class, которое есть у всех типов, возвращает объект Class, который представляет этот тип:
public class Program{
public static void main(String[] args) {
Class personClass = Person.class;
System.out.println(personClass); // class Person
Class strClass = String.class;
System.out.println(strClass); // class java.lang.String
}
}
class Person{ }