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 |
|---|---|
|
Um array de todos os campos public da classe, de seus pais e interfaces |
|
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 |
|---|---|
|
Todos os métodos public da classe e de seus pais (incluindo Object) |
|
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 |
|---|---|
|
Todos os construtores public |
|
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 | |
| Todos os campos declarados | |
| Todos os métodos public | |
| Todos os métodos declarados | |
| Todos os construtores public | |
| Todos os construtores declarados | |
| Anotações da classe | |
| Anotações de método/campo | |
| Modificadores | |
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.
GO TO FULL VERSION