CodeGym /Cursos /JAVA 25 SELF /Obtendo informações sobre classes, campos e métodos

Obtendo informações sobre classes, campos e métodos

JAVA 25 SELF
Nível 62 , Lição 1
Disponível

1. Obtendo informações sobre campos

Qual é a diferença entre getFields() e getDeclaredFields()

Em Java, toda classe tem campos (fields) — variáveis declaradas dentro da classe. Com reflexão podemos descobrir seus nomes, tipos, modificadores de acesso (public/private) e também acessá-los em tempo de execução. O ponto de entrada principal é o objeto Class<?>.

Métodos principais da classe Class para trabalhar com campos:

Método O que retorna
getFields()
Um array de todos os campos public da classe, de seus pais e interfaces
getDeclaredFields()
Um array de todos os campos declarados nesta classe

Analogia: getFields() é como um tour apenas pelas salas de exposição (public), enquanto getDeclaredFields() inclui também as áreas técnicas (private, protected, package-private).

Exemplo: imprimir todos os campos da classe

Suponha que temos a classe:

public class Person {
    public String name;
    private int age;
    protected String email;
}

Vamos obter informações sobre os campos:

import java.lang.reflect.Field;

Class<?> clazz = Person.class;

// Todos os campos public (incluindo os herdados)
System.out.println("Public fields:");
for (Field field : clazz.getFields()) {
    System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}

// Todos os campos declarados (incluindo private; apenas os próprios)
System.out.println("\nDeclared fields:");
for (Field field : clazz.getDeclaredFields()) {
    System.out.println(field.getName() + " : " + field.getType().getSimpleName());
}

Resultado:

Public fields:
name : String

Declared fields:
name : String
age : int
email : String

Como obter os modificadores de um campo?

Cada campo (Field) tem modificadores (public/private/protected, static, final etc.). É possível obtê-los via getModifiers() e convertê-los para string com Modifier:

import java.lang.reflect.Modifier;

for (Field field : clazz.getDeclaredFields()) {
    int mods = field.getModifiers();
    System.out.println(field.getName() + " : " + Modifier.toString(mods));
}

2. Obtendo informações sobre métodos

Métodos getMethods() e getDeclaredMethods()

Métodos são as ações que um objeto pode executar. Com reflexão, você pode descobrir quais métodos a classe possui, seus parâmetros, tipos de retorno, modificadores e anotações.

Método O que retorna
getMethods()
Todos os métodos public da classe e de seus pais (incluindo Object)
getDeclaredMethods()
Todos os métodos declarados nesta classe (incluindo private)

Exemplo: imprimir todos os métodos da classe

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());
}

Resultado (para Person):

Public methods:
getClass
hashCode
equals
toString
notify
notifyAll
wait
wait
wait

Declared methods:
(nada, se Person não declarar seus próprios métodos)

Vamos adicionar um método em Person:

public class Person {
    public String name;
    private int age;
    protected String email;

    public void sayHello() {
        System.out.println("Hi!");
    }
}

Agora getDeclaredMethods() também o exibirá.

Como obter os parâmetros e o tipo de retorno de um método?

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(");");
}

Saída:

public void sayHello();

3. Obtendo informações sobre construtores

Construtores são métodos especiais usados para criar objetos.

Método O que retorna
getConstructors()
Todos os construtores public
getDeclaredConstructors()
Todos os construtores declarados na classe

Exemplo: imprimir todos os construtores da classe

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(");");
}

Se a classe declarar apenas o construtor padrão, ele também será exibido.

4. Anotações: como saber com o que uma classe, método ou campo está anotado

Anotações são marcadores especiais que podem ser aplicados a classes, métodos, campos e parâmetros. Com reflexão é possível saber quais anotações um elemento possui.

Obtendo anotações

  • Para a classe: clazz.getAnnotations()
  • Para o método: method.getAnnotations()
  • Para o campo: field.getAnnotations()

Exemplo: verificar se a anotação @Deprecated está presente

for (Method method : clazz.getDeclaredMethods()) {
    if (method.isAnnotationPresent(Deprecated.class)) {
        System.out.println(method.getName() + " is @Deprecated");
    }
}

Exemplo: imprimir todas as anotações da classe

for (var annotation : clazz.getAnnotations()) {
    System.out.println(annotation);
}

5. Prática: miniaplicativo para analisar a estrutura de uma classe

Vamos juntar tudo e escrever um pequeno utilitário que, dado o nome da classe, imprime sua estrutura: campos, métodos, construtores e anotações.

Exemplo de código: 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("Digite o nome completo da classe (por exemplo, java.util.ArrayList): ");
        String className = scanner.nextLine();

        Class<?> clazz = Class.forName(className);

        System.out.println("\n== Classe: " + clazz.getName() + " ==");

        // Anotações da classe
        System.out.println("Anotações:");
        for (Annotation annotation : clazz.getAnnotations()) {
            System.out.println("  " + annotation);
        }

        // Campos
        System.out.println("\nCampos:");
        for (Field field : clazz.getDeclaredFields()) {
            System.out.println("  " + Modifier.toString(field.getModifiers())
                    + " " + field.getType().getSimpleName()
                    + " " + field.getName());
        }

        // Métodos
        System.out.println("\nMétodos:");
        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(");");
        }

        // Construtores
        System.out.println("\nConstrutores:");
        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(");");
        }
    }
}

Como isso funciona?

  • O usuário digita o nome completo da classe (por exemplo, "java.util.ArrayList" ou uma classe própria).
  • O programa carrega a classe dinamicamente e imprime suas anotações, campos, métodos e construtores.
  • Experimente com classes padrão do JDK — você verá quanta coisa interessante está escondida lá dentro!

6. Dicas úteis e visualização

Diagrama visual: o que é possível saber sobre uma classe via reflexão

graph TD
    A[Class<?>] --> B["getFields/getDeclaredFields"]
    A --> C[getMethods/getDeclaredMethods]
    A --> D[getConstructors/getDeclaredConstructors]
    A --> E[getAnnotations]
    B --> F[Field: tipo, nome, modificadores]
    C --> G[Method: tipo de retorno, parâmetros]
    D --> H[Constructor: parâmetros]
    E --> I["Annotation[]"]

Tabela: onde buscar informações

O que queremos saber Como obter via reflexão
Todos os campos public
clazz.getFields()
Todos os campos declarados
clazz.getDeclaredFields()
Todos os métodos public
clazz.getMethods()
Todos os métodos declarados
clazz.getDeclaredMethods()
Todos os construtores public
clazz.getConstructors()
Todos os construtores declarados
clazz.getDeclaredConstructors()
Anotações da classe
clazz.getAnnotations()
Anotações de método/campo
method.getAnnotations(), field.getAnnotations()
Modificadores
Modifier.toString(field.getModifiers())

7. Erros comuns ao trabalhar com reflexão

Erro nº 1: Confundir getFields() com getDeclaredFields().
Se você procura campos private, use getDeclaredFields(), e não getFields(). O primeiro retorna todos os campos declarados na classe, enquanto o segundo — apenas os public (e os herdados!).

Erro nº 2: Não tratar exceções checked.
Muitos métodos de reflexão lançam exceções (por exemplo, ClassNotFoundException ou SecurityException). Não se esqueça de tratá-las ou declará-las na assinatura do método.

Erro nº 3: Ignorar os modificadores de acesso.
O acesso a private-campos e métodos só é possível após chamar setAccessible(true); caso contrário, ocorrerá IllegalAccessException. Exemplo:

Field field = clazz.getDeclaredField("age");
field.setAccessible(true); // Abrindo acesso ao campo private
int value = (int) field.get(person);

Erro nº 4: Esperar ver apenas seus próprios métodos/campos.
getMethods() e getFields() retornam membros public não apenas da classe atual, mas também de todos os seus pais, incluindo Object. Isso pode surpreender se você esperava ver somente o que escreveu.

Erro nº 5: Verificar a presença de anotações de forma incorreta.
Use isAnnotationPresent() para verificar uma anotação específica, em vez de iterar manualmente pelo array de anotações sem necessidade.

Comentários
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION