1. O que é reflexão
Reflexão em Java é um mecanismo que permite que um programa investigue e até altere sua própria estrutura em tempo de execução. É como se você pudesse olhar para dentro de si e descobrir: “Quais campos e métodos eu tenho? Qual é o meu construtor? Que classe eu sou afinal?” — e até invocar um método privado em si mesmo.
Definição formal:
Reflexão é um API que permite obter informações sobre classes, interfaces, campos, métodos e construtores em tempo de execução do programa, bem como trabalhar com eles.
Para que serve a reflexão?
- Frameworks: Spring, Hibernate, JUnit usam reflexão para “mágica”: criação automática de objetos, injeção de dependências, chamada de métodos por nome e por anotações.
- Serialização: Transformar objetos em JSON/XML e vice‑versa — é preciso descobrir os campos e saber acessá‑los.
- Testes: Encontrar e invocar automaticamente métodos anotados (por exemplo, @Test).
- Carregamento dinâmico de classes: Carregar uma classe pelo nome em tempo de execução (plugins, drivers).
- IDEs e análise de código: Autocompletar, inspeções, refatoração.
Exemplo da vida real
public class Person {
private String name;
private int age;
public void sayHello() {
System.out.println("Olá, meu nome é " + name);
}
}
Com reflexão, podemos, em tempo de execução, descobrir que a classe Person tem os campos name e age, bem como o método sayHello. Além disso, é possível alterar o valor de um campo privado ou invocar um método pelo nome.
Um pouco de humor
Pode‑se dizer que reflexão é como em “Matrix”: você percebe que todo o seu código são dados que podem ser investigados e alterados em tempo real. Só não se esqueça da pílula vermelha da segurança!
2. A classe Class: o coração da reflexão
Em Java, cada objeto e cada tipo, em tempo de execução, está associado a um objeto especial do tipo Class. Esse objeto é a “metainformação” sobre o tipo. A classe java.lang.Class<T> é o ponto de entrada central no mundo da reflexão.
Como obter um objeto Class?
Há várias maneiras:
- Por .class
A maneira mais direta e segura, se a classe for conhecida em tempo de compilação:Class<Person> personClass = Person.class; - A partir de um objeto: getClass()
Se você já tem uma instância:
Aqui, clazz é um objeto Class que descreve a classe real do objeto p.Person p = new Person(); Class<?> clazz = p.getClass(); - A partir de uma string: Class.forName()
Se o nome da classe é conhecido apenas em tempo de execução:
Adequado para carregar plugins, drivers e outros componentes dinâmicos.Class<?> clazz = Class.forName("com.example.Person");
Exemplo: obtendo o nome da classe
Person p = new Person();
Class<?> clazz = p.getClass();
System.out.println(clazz.getName()); // Irá imprimir: Person ou com.example.Person
Tabela: principais maneiras de obter um objeto Class
| Como obter | Quando usar | Exemplo |
|---|---|---|
|
Se a classe é conhecida em tempo de compilação | |
|
Se você tem um objeto | |
|
Se o nome da classe é conhecido em tempo de execução | |
Esquema: o objeto e seu Class
+-------------------+
| Person p |
+-------------------+
|
v
+-------------------+
| p.getClass() |
+-------------------+
|
v
+-------------------+
| Class<Person> |
+-------------------+
Verificação de tipo via Class
Às vezes é necessário saber se um objeto pertence a uma classe específica:
if (p.getClass() == Person.class) {
System.out.println("É definitivamente Person!");
}
Ou considerando a herança — o operador comum instanceof:
if (p instanceof Person) {
// funciona normalmente
}
3. Quando usar reflexão — e quando não usar
Com grandes poderes vem grande responsabilidade. Reflexão é uma ferramenta poderosa, mas use‑a apenas quando for realmente necessário.
Onde a reflexão é necessária
- Frameworks e bibliotecas: Spring, Hibernate, JUnit, Jackson — automação, “mágica” e menos código “manual”.
- Serialização: É preciso descobrir os campos do objeto para transformá‑lo em JSON/XML.
- Plugins e extensões: As classes são carregadas dinamicamente e sua estrutura é desconhecida de antemão.
Por que não abusar da reflexão
- Perda de segurança de tipos: Erros aparecem em tempo de execução.
- Manutenção mais difícil: O código fica menos óbvio.
- Desempenho: Mais lento que chamadas diretas.
- Segurança: É possível contornar a encapsulação e expor dados privados.
Exemplo: quando a reflexão não é necessária
p.sayHello();
Exemplo: quando a reflexão é indispensável
Você está escrevendo um mini‑framework de testes: o usuário marca métodos com a anotação @Test, e o programa deve encontrá‑los e chamá‑los automaticamente — sem reflexão, impossível.
4. Demonstração: conhecendo o Class
Exemplo: imprimir o nome da classe e sua superclasse
public class ReflectionDemo {
public static void main(String[] args) {
String s = "Hello, reflection!";
Class<?> clazz = s.getClass();
System.out.println("Nome da classe: " + clazz.getName());
System.out.println("Nome simples da classe: " + clazz.getSimpleName());
System.out.println("Pacote: " + clazz.getPackageName());
System.out.println("Superclasse: " + clazz.getSuperclass().getName());
}
}
Resultado:
Nome da classe: java.lang.String
Nome simples da classe: String
Pacote: java.lang
Superclasse: java.lang.Object
Exemplo: obtendo Class para tipos primitivos
Class<Integer> intClass = int.class;
System.out.println(intClass.getName()); // int
Class<?> doubleClass = double.class;
System.out.println(doubleClass.getName()); // double
Exemplo: obtendo Class para um array
int[] arr = new int[10];
Class<?> arrClass = arr.getClass();
System.out.println(arrClass.getName()); // [I (formato específico para arrays)
Exemplo: verificando pertencimento a um tipo
if (arrClass.isArray()) {
System.out.println("É um array!");
}
5. Prática: mini‑programa “Que classe é esta?”
Vamos escrever um programa que recebe o nome completo de uma classe (por exemplo, "java.util.ArrayList") e imprime informações básicas sobre ela.
import java.util.Scanner;
public class ClassInfoPrinter {
public static void main(String[] args) throws Exception {
Scanner scanner = new Scanner(System.in);
System.out.print("Digite o nome completo da classe: ");
String className = scanner.nextLine();
Class<?> clazz = Class.forName(className);
System.out.println("Nome da classe: " + clazz.getName());
System.out.println("Pacote: " + clazz.getPackageName());
System.out.println("Superclasse: " + clazz.getSuperclass().getName());
Class<?>[] interfaces = clazz.getInterfaces();
System.out.print("Implementa as interfaces: ");
for (Class<?> i : interfaces) {
System.out.print(i.getName() + " ");
}
System.out.println();
}
}
Exemplo de execução:
Digite o nome completo da classe: java.util.ArrayList
Nome da classe: java.util.ArrayList
Pacote: java.util
Superclasse: java.util.AbstractList
Implementa as interfaces: java.util.List java.util.RandomAccess java.lang.Cloneable java.io.Serializable
Fatos interessantes sobre Class e reflexão
- Cada tipo carregado na JVM tem um único representante — um objeto Class. Todas as instâncias do mesmo tipo compartilham o mesmo Class<T>.
- É possível determinar o tipo: isInterface(), isEnum(), isArray(), isPrimitive() etc.
- Se você informar um nome incorreto em Class.forName, receberá a exceção ClassNotFoundException.
- Com reflexão é possível criar objetos, mesmo sem conhecer a classe em tempo de compilação — falaremos disso na próxima aula.
6. Erros típicos no primeiro contato com reflexão
Erro nº 1: esperar que reflexão seja rápida.
Na verdade, reflexão é mais lenta do que chamadas de métodos e acesso a campos “normais”. Não a utilize para cada pequena tarefa.
Erro nº 2: tentar obter Class de uma classe inexistente.
Se você errar o nome, receberá ClassNotFoundException. Trate essa exceção.
Erro nº 3: confundir o objeto da classe com uma instância.
O objeto Class descreve a estrutura do tipo; ele não é uma instância do tipo.
Erro nº 4: usar reflexão sem necessidade.
Se é possível resolver com código “comum”, prefira assim. Reflexão é necessária para dinamicidade, frameworks, plugins e tarefas semelhantes.
Erro nº 5: manipular campos e métodos privados de forma descuidada.
A reflexão permite contornar a encapsulação, o que pode levar a erros e problemas de segurança, especialmente em projetos grandes.
GO TO FULL VERSION