Visão Geral dos Membros em Java: Fields, Methods e Constructors
Para aprofundar a análise de tipos com Reflection, a API do Java oferece um conjunto de classes, localizadas no pacote java.lang.reflect
, que permitem uma inspeção detalhada dos membros de uma classe:
Field
: Representa um campo (variável de membro).Method
: Representa um método.Constructor
: Representa um construtor.
Para obter objetos que representam esses membros, a classe Class
oferece dois grupos de métodos com uma distinção fundamental:
- Membros Públicos e Herdados: Os métodos
getFields()
,getMethods()
egetConstructors()
retornam apenas os membros públicos (public
) de uma classe, incluindo os membros públicos herdados de suas superclasses. - Todos os Membros Declarados (Não Herdados): Os métodos
getDeclaredFields()
,getDeclaredMethods()
egetDeclaredConstructors()
retornam todos os membros (públicos, privados, etc.) declarados diretamente na classe. A principal diferença é que eles não incluem membros herdados.
A escolha entre esses dois grupos de métodos é crucial e depende se a análise precisa incluir membros herdados e se é necessário acessar membros não públicos.
Vamos considerar a seguinte classe Person
para os exemplos:
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public int getAge() {
return age;
}
public Person() {
this.name = "Undefined";
this.age = 18;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
Análise de Membros Públicos e Herdados
Neste exemplo, inspecionamos a classe Person
usando os métodos que retornam apenas os membros públicos e herdados.
import java.lang.reflect.*;
public class Program {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
Field[] fields = personClass.getFields();
Method[] methods = personClass.getMethods();
Constructor<?>[] ctors = personClass.getConstructors();
System.out.println("Public Fields (getFields):");
for (Field field : fields) {
System.out.println(field);
}
System.out.println("\nPublic Constructors (getConstructors):");
for (Constructor<?> ctor : ctors) {
System.out.println(ctor);
}
System.out.println("\nPublic Methods (getMethods):");
for (Method method : methods) {
System.out.println(method);
}
}
}
O resultado da execução será:
Public Fields (getFields): Public Constructors (getConstructors): public Person(java.lang.String,int) public Person() Public Methods (getMethods): public java.lang.String Person.getName() public int Person.getAge() public final void java.lang.Object.wait() throws java.lang.InterruptedException // ... e outros métodos herdados de java.lang.Object
Note que:
- A lista de campos está vazia, pois
getFields()
só retorna membros públicos, e os camposname
eage
sãoprivate
. - A lista de métodos é extensa, pois
getMethods()
inclui todos os métodos públicos herdados da classeObject
.
Análise de Membros Declarados na Classe
Agora, usamos o segundo grupo de métodos para obter todos os membros declarados diretamente na classe Person
, independentemente do modificador de acesso.
import java.lang.reflect.*;
public class Program {
public static void main(String[] args) {
Class<Person> personClass = Person.class;
Field[] fields = personClass.getDeclaredFields();
Method[] methods = personClass.getDeclaredMethods();
Constructor<?>[] ctors = personClass.getDeclaredConstructors();
System.out.println("Declared Fields (getDeclaredFields):");
for (Field field : fields) {
System.out.println(field);
}
System.out.println("\nDeclared Constructors (getDeclaredConstructors):");
for (Constructor<?> ctor : ctors) {
System.out.println(ctor);
}
System.out.println("\nDeclared Methods (getDeclaredMethods):");
for (Method method : methods) {
System.out.println(method);
}
}
}
A saída agora é bem diferente:
Declared Fields (getDeclaredFields): private java.lang.String Person.name private int Person.age Declared Constructors (getDeclaredConstructors): public Person(java.lang.String,int) public Person() Declared Methods (getDeclaredMethods): public java.lang.String Person.getName() public int Person.getAge()
Desta vez, a saída é diferente:
- Os campos
private
name
eage
são listados, poisgetDeclaredFields()
acessa todos os membros declarados, independentemente do modificador de acesso. - A lista de métodos e construtores contém apenas aqueles definidos em
Person
, sem incluir os membros herdados deObject
.
Verificação de Características do Tipo
A classe Class
também oferece métodos para verificar as características do tipo analisado.
public class Program {
public static void main(String[] args) {
Class<Person> cl = Person.class;
System.out.println("Name: " + cl.getName());
System.out.println("Superclass: " + cl.getSuperclass());
System.out.println("Is record: " + cl.isRecord());
Person tom = new Person("Tom", 41);
System.out.println("Is tom an instance of Person: " + cl.isInstance(tom));
String message = "hello";
System.out.println("Is message an instance of Person: " + cl.isInstance(message));
}
}
// Usando um record para este exemplo
record Person(String name, int age) {}
A execução deste código produzirá o seguinte resultado:
Name: Person Superclass: class java.lang.Record Is record: true Is tom an instance of Person: true Is message an instance of Person: false
A saída confirma que Person
é um record
e que o método isInstance()
funciona de maneira análoga ao operador instanceof
.
Resumo
- Inspeção de Membros: A API de Reflection permite a inspeção detalhada de campos, métodos e construtores em tempo de execução.
- Visibilidade e Herança: A escolha entre métodos como
getFields()
(públicos e herdados) egetDeclaredFields()
(todos os declarados, mas não herdados) é fundamental e depende do objetivo da análise. - Acesso a Membros Privados: Os métodos
getDeclared...()
são a porta de entrada para acessar e manipular membros privados, um dos recursos mais poderosos da Reflection. - Verificação de Tipos: A classe
Class
oferece vários métodosis...()
para verificar as características de um tipo (se é umrecord
,interface
, etc.).