1. Получение информации о полях
Чем отличаются getFields() и getDeclaredFields()
В Java у каждого класса есть поля (fields) — переменные, объявленные внутри класса. С помощью рефлексии мы можем узнать их имена, типы, модификаторы доступа (public/private), а также получить к ним доступ во время выполнения. Основной вход — объект Class<?>.
Основные методы класса Class для работы с полями:
| Метод | Что возвращает |
|---|---|
|
Массив всех public-полей класса, его родителей и интерфейсов |
|
Массив всех полей, объявленных в этом классе |
Аналогия: getFields() — как экскурсия только по выставочным залам (public), а getDeclaredFields() — ещё и по техническим помещениям (private, protected, package-private).
Пример: выводим все поля класса
Допустим, у нас есть класс:
public class Person {
public String name;
private int age;
protected String email;
}
Получим информацию о полях:
import java.lang.reflect.Field;
Class<?> clazz = Person.class;
// Все public-поля (включая унаследованные)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
// Все объявленные поля (включая private, только свои)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}
Результат:
Public fields:
name : String
Declared fields:
name : String
age : int
email : String
Как узнать модификаторы поля?
Каждое поле (Field) имеет модификаторы (public/private/protected, static, final и т.д.). Их можно получить через getModifiers() и преобразовать в строку с помощью Modifier:
import java.lang.reflect.Modifier;
for (Field field : clazz.getDeclaredFields()) {
int mods = field.getModifiers();
System.out.println(field.getName() + " : " + Modifier.toString(mods));
}
2. Получение информации о методах
Методы getMethods() и getDeclaredMethods()
Методы — это действия, которые может выполнять объект. С помощью рефлексии можно узнать, какие методы есть у класса, их параметры, возвращаемые типы, модификаторы и аннотации.
| Метод | Что возвращает |
|---|---|
|
Все public методы класса и его родителей (включая Object) |
|
Все методы, объявленные в этом классе (включая private) |
Пример: выводим все методы класса
import java.lang.reflect.Method;
System.out.println("Public methods:");
for (Method method : clazz.getMethods()) {
System.out.println(method.getName());
}
System.out.println("\nDeclared methods:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.println(method.getName());
}
Результат (для Person):
Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait
Declared methods:
(ничего, если в Person не объявлено своих методов)
Добавим метод в Person:
public class Person {
public String name;
private int age;
protected String email;
public void sayHello() {
System.out.println("Hi!");
}
}
Теперь getDeclaredMethods() покажет и его.
Как узнать параметры и возвращаемый тип метода?
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(Modifier.toString(method.getModifiers()) + " ");
System.out.print(method.getReturnType().getSimpleName() + " ");
System.out.print(method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Вывод:
public void sayHello();
3. Получение информации о конструкторах
Конструкторы — это специальные методы, которые используются для создания объектов.
| Метод | Что возвращает |
|---|---|
|
Все public конструкторы |
|
Все конструкторы, объявленные в классе |
Пример: выводим все конструкторы класса
import java.lang.reflect.Constructor;
System.out.println("Constructors:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
Если в классе объявлен только конструктор по умолчанию, он тоже будет выведен.
4. Аннотации: как узнать, чем помечен класс, метод или поле
Аннотации — это специальные метки, которые можно навешивать на классы, методы, поля и параметры. С помощью рефлексии можно узнать, какие аннотации есть у элемента.
Получение аннотаций
- Для класса: clazz.getAnnotations()
- Для метода: method.getAnnotations()
- Для поля: field.getAnnotations()
Пример: проверим наличие аннотации @Deprecated
for (Method method : clazz.getDeclaredMethods()) {
if (method.isAnnotationPresent(Deprecated.class)) {
System.out.println(method.getName() + " is @Deprecated");
}
}
Пример: выводим все аннотации класса
for (var annotation : clazz.getAnnotations()) {
System.out.println(annotation);
}
5. Практика: мини-программа для анализа структуры класса
Давайте соберём всё вместе и напишем небольшую утилиту, которая по имени класса выводит его структуру: поля, методы, конструкторы и аннотации.
Пример кода: ClassInspector
import java.lang.reflect.*;
import java.util.Scanner;
public class ClassInspector {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("Введите полное имя класса (например, java.util.ArrayList): ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("\n== Класс: " + clazz.getName() + " ==");
// Аннотации класса
System.out.println("Аннотации:");
for (Annotation annotation : clazz.getAnnotations()) {
System.out.println(" " + annotation);
}
// Поля
System.out.println("\nПоля:");
for (Field field : clazz.getDeclaredFields()) {
System.out.println(" " + Modifier.toString(field.getModifiers())
+ " " + field.getType().getSimpleName()
+ " " + field.getName());
}
// Методы
System.out.println("\nМетоды:");
for (Method method : clazz.getDeclaredMethods()) {
System.out.print(" " + Modifier.toString(method.getModifiers())
+ " " + method.getReturnType().getSimpleName()
+ " " + method.getName() + "(");
Class<?>[] params = method.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
// Конструкторы
System.out.println("\nКонструкторы:");
for (Constructor<?> constructor : clazz.getDeclaredConstructors()) {
System.out.print(" " + Modifier.toString(constructor.getModifiers())
+ " " + clazz.getSimpleName() + "(");
Class<?>[] params = constructor.getParameterTypes();
for (int i = 0; i < params.length; i++) {
System.out.print(params[i].getSimpleName());
if (i < params.length - 1) System.out.print(", ");
}
System.out.println(");");
}
}
}
Как это работает?
- Пользователь вводит полное имя класса (например, "java.util.ArrayList" или свой класс).
- Программа динамически загружает класс и выводит его аннотации, поля, методы и конструкторы.
- Попробуйте на стандартных классах JDK — увидите, сколько всего интересного скрыто внутри!
6. Полезные нюансы и визуализация
Визуальная схема: что можно узнать о классе через рефлексию
Таблица: где искать информацию
| Что хотим узнать | Как получить через рефлексию |
|---|---|
| Все public-поля | |
| Все объявленные поля | |
| Все public-методы | |
| Все объявленные методы | |
| Все public-конструкторы | |
| Все объявленные конструкторы | |
| Аннотации класса | |
| Аннотации метода/поля | |
| Модификаторы | |
7. Типичные ошибки при работе с рефлексией
Ошибка №1: Путают getFields() и getDeclaredFields().
Если вы ищете private-поля, используйте getDeclaredFields(), а не getFields(). Первый возвращает все поля, объявленные в классе, а второй — только public (и унаследованные!).
Ошибка №2: Не обрабатывают checked-исключения.
Многие методы рефлексии бросают исключения (например, ClassNotFoundException или SecurityException). Не забывайте обрабатывать их или объявлять в сигнатуре метода.
Ошибка №3: Не учитывают модификаторы доступа.
Доступ к private-полям и методам возможен только после вызова setAccessible(true), иначе будет IllegalAccessException. Пример:
Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // Открываем доступ к private-полю
int value = (int) field.get(person);
Ошибка №4: Ожидают увидеть только свои методы/поля.
getMethods() и getFields() возвращают public-члены не только текущего класса, но и всех его родителей, включая Object. Это может удивить, если вы ожидаете увидеть только то, что написали сами.
Ошибка №5: Не проверяют наличие аннотаций правильно.
Используйте isAnnotationPresent() для проверки конкретной аннотации, а не перебирайте вручную массив аннотаций без нужды.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ