JavaRush /Курси /JAVA 25 SELF /Отримання інформації про класи, поля, методи

Отримання інформації про класи, поля, методи

JAVA 25 SELF
Рівень 62 , Лекція 1
Відкрита

1. Отримання інформації про поля

Чим відрізняються getFields() і getDeclaredFields()?

У Java кожен клас має поля (fields) — змінні, оголошені всередині класу. За допомогою рефлексії ми можемо дізнатися їхні імена, типи, модифікатори доступу (public/private), а також отримати до них доступ під час виконання. Основна точка входу — об’єкт Class<?>.

Основні методи класу Class для роботи з полями:

Метод Що повертає
getFields()
Масив усіх public-полів класу, його батьків і інтерфейсів
getDeclaredFields()
Масив усіх полів, оголошених у цьому класі

Аналогія: 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()

Методи — це дії, які може виконувати об’єкт. За допомогою рефлексії можна дізнатися, які методи є у класі, їхні параметри, тип, що повертається, модифікатори й анотації.

Метод Що повертає
getMethods()
Усі public-методи класу та його батьків (включно з Object)
getDeclaredMethods()
Усі методи, оголошені в цьому класі (включно з 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. Отримання інформації про конструктори

Конструктори — це спеціальні методи, які використовуються для створення об’єктів.

Метод Що повертає
getConstructors()
Усі public-конструктори
getDeclaredConstructors()
Усі конструктори, оголошені в класі

Приклад: виведемо всі конструктори класу

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. Корисні нюанси та візуалізація

Візуальна схема: що можна дізнатися про клас за допомогою рефлексії

graph TD A[Class<?>] --> B["getFields/getDeclaredFields"] A --> C[getMethods/getDeclaredMethods] A --> D[getConstructors/getDeclaredConstructors] A --> E[getAnnotations] B --> F[Field: тип, ім’я, модифікатори] C --> G[Method: тип, що повертається, параметри] D --> H[Constructor: параметри] E --> I["Annotation[]"]

Таблиця: де шукати інформацію

Що хочемо дізнатися Як отримати через рефлексію
Усі public-поля
clazz.getFields()
Усі оголошені поля
clazz.getDeclaredFields()
Усі public-методи
clazz.getMethods()
Усі оголошені методи
clazz.getDeclaredMethods()
Усі public-конструктори
clazz.getConstructors()
Усі оголошені конструктори
clazz.getDeclaredConstructors()
Анотації класу
clazz.getAnnotations()
Анотації методу/поля
method.getAnnotations(), field.getAnnotations()
Модифікатори
Modifier.toString(field.getModifiers())

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() для перевірки конкретної анотації, а не перебирайте вручну масив анотацій без потреби.

Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ