Pergunta

O que é a Reflexão (Reflection)?

Resposta

A Reflexão Java ou simplesmente Reflection é uma API do Java destinada a permitir que o código Java obtenha em tempo de execução informações sobre classes, seus campos, métodos e construtores, permitindo a manipulação dinâmica de código. Desta forma é destinada primariamente para ser utilizada por ferramentas especiais tais como depuradores (debuggers), interpretadores ou inspetores de classes e objetos.

Esta API, java.lang.reflect, pode ser utilizada para:

Apesar disso não se recomenda seu uso quando os mecanismos usuais da linguagem são suficientes para efetuar as operações desejadas.

Através do pacote java.lang.reflect temos acesso as classes Field, Method e Constructor que possibilitam determinar respectivamente quais os campos, métodos e construtores através de um ou mais métodos. Segue um exemplo que permite obter informações sobre os campos, consutores e métodos declarados em uma classe, cujo nome é fornecido como argumento da aplicação:

// ClassInfo.java

import java.lang.reflect.*;

public class ClassInfo {

  public static void main(String args[]) {
    // Verifica se foi dado um argumento
    if (args.length==0) {
      System.out.println("Uso:\n\tClassInfo <pacote.NomeClasse>");
      System.exit(1);
    }
    try {
      // Carrega classe dinamicamente
      Class classe = Class.forName(args[0]);

      // Obtêm enumeração dos campos declarados
      Field campos[] = classe.getDeclaredFields();
      // Obtêm enumeração dos contrutores declarados
      Constructor construtores[] = classe.getDeclaredConstructors();
      // Obtêm enumeração dos métodos declarados
      Method metodos[] = classe.getDeclaredMethods();

      int i;
      // Exibe campos
      System.out.println("Campos:");
      for (i=0; i<campos.length; i++)
        System.out.println(campos[i].toString());
      // Exibe construtores
      System.out.println("Construtores:");
      for (i=0; i<construtores.length; i++)
        System.out.println(construtores[i].toString());
      // Exibe métodos
      System.out.println("Metodos:");
      for (i=0; i<metodos.length; i++)
        System.out.println(metodos[i].toString());
    } catch (ClassNotFoundException e) {
      System.out.println("Classe não encontrada: " + e);
    }
  }
}

O resultado desta aplicação para a classe java.lang.Number pode ser visto abaixo:

>java ClassInfo java.lang.Number
Campos:
private static final long java.lang.Number.serialVersionUID
Construtores:
public java.lang.Number()
Metodos:
public abstract int java.lang.Number.intValue()
public abstract long java.lang.Number.longValue()
public abstract float java.lang.Number.floatValue()
public abstract double java.lang.Number.doubleValue()
public byte java.lang.Number.byteValue()
public short java.lang.Number.shortValue()

Ainda utilizando características da API de reflexão, podemos determinar qual a hierarquia de uma classes, isto é, qual sua(s) superclasse(s):

// ClassFamily.java

import java.util.*;

public class ClassFamily {

  public static void main(String args[]) throws Exception {
    // Verifica se foi dado um argumento
    if (args.length==0) {
      System.out.println("Usage:\n\tClassFamily <pacote.NomeClasse>");
      System.exit(1);
    }
    Class classe = null;

    // Carrega classe dinamicamente
    classe = Class.forName(args[0]);

    // Determina hierarquia até java.lang.Object
    Vector hierarquia = new Vector(10);
    do {
        hierarquia.addElement(classe);
        classe = classe.getSuperclass();
    } while (classe != null);

    // Exibe hierarquia
    int i = hierarquia.size()-1;
    System.out.println((""+(Class)hierarquia.elementAt(i--)).substring(6));
    StringBuffer espacos = new StringBuffer("   ");
    for (; i>=0; i--) {
      System.out.print(espacos+"|\n"+espacos+"+----");
      System.out.println((""+(Class)hierarquia.elementAt(i)).substring(6));
      espacos.append("        ");
    }
  }
}

O resultado desta aplicação para a classe java.lang.Float pode ser visto abaixo:

>java ClassFamily java.lang.Float
java.lang.Object
   |
   +----java.lang.Number
           |
           +----java.lang.Float