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() для перевірки конкретної анотації, а не перебирайте вручну масив анотацій без потреби.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ