Java e Reflection

em 03/09/2002 , por Daniel Destro
Usando Java Reflection
Hoje a tecnologia Java proporciona inúmeras funcionalidades que fazem frente à qualquer outra tecnologia, e uma das coisas mais fascinantes e produtivas do Java é a Reflection, uma característica intrínseca desta tecnologia e que existe em poucas outras como existe nessa. Ela está presente no Java desde a versão 1.1. A Reflection permite um programa Java examinar ou fazer a introspecção nele mesmo, ou seja, olhar e examinar suas propriedades e estrutura. Com isso, você pode, por exemplo obter o nome de todos os membros de uma classe, como atributos e métodos, bem como executar um método usando a Introspection. É deste modo que os aplicativos de ambiente de desenvolvimento (as IDEs) conseguem examinar e exibir a estrutura e conteúdo das classes e beans. Para este tutorial, é necessário que você tenha uma boa familiarização com o Java, e em especial, que conheça o básico da classe java.lang.Class, a qual guarda informações sobre uma determinada classe. Este tutorial, diferente dos outros, apresentará o código mais completo, ao invés de trechos, já que dependemos do código inteiro para mostrar o que estamos "refletindo". Então não se assuste com o tamanho dos códigos. Para compreendermos melhor esta feature do Java, vamos dar uma olhada no códigos de exemplo que se seguem.
Listando os métodos de uma classe


O código acima é bem simples e sua função é de apenas listar os métodos da classe java.lang.String, ou melhor, ele lista a assinatura dos métodos da classe, como o tipo de retorno e os parâmetros do método, com a estrutura completa dos pacotes dos tipos (fully qualified type). Carregamos a classe com o método Class.forName e então, como o método getDeclaredMethods pegamos uma lista com os métodos. Ainda, com o método getMethods, lista os métodos herdados das classes pai (superclasse) da classe que está sendo observada.
Instanceof - Comparação de tipos
Usando Reflection é ainda possível fazer o uso do instanceof, de uma maneira diferente da tradicional. Vejamos:

Obtendo informações mais precisas sobre os métodos
Indo mais a fundo no uso da Reflection, podemos fazer uma maior detalhamento dos métodos membros da classe analisada, ou seja, para cada método examinado podemos verificar os modificadores, o nome do método, o tipo de retorno, os parâmetros do método e as exceções que o método pode lançar. Vejamos código de exemplo:

Este simples código realmente "depena" um método, retornando toda a informação sobre ele.
Construtores
Com a Reflection ainda é possível obter informação sobre os construtores da classe analisada. Neste caso não há informação sobre o tipo de retorno, pois os construtores de classe não definem um tipo de retorno (óbvio). Veja o código:

Atributos
É possível ainda fazer uma introspecção afim de obter os dados e informações sobre os atributos membros da classe, como os modificadores, tipo e o nome dos atributos. Conforme o código:

Invocando métodos pelo nome
Uma parte interessantíssima do Java Reflection é invocar um método pelo seu nome, ou seja, fornecendo o nome do método para a execução. Veja o exemplo abaixo:

No exemplo acima o método getMethod é usado para achar o método da classe pelo nome informado ("umMetodo") contendo os parâmetros informados. Uma vez achado o método e capturado pelo objeto to tipo Method, ele é invocado sob uma instância do objeto do seu tipo correto. Uma lista de parâmetros também deve ser passada, correspondentes aos parâmetros e tipos do método requisitado. As exceções que o Method.invoke() pode lançar são diversas: uma é a respeito de segurança, se, por exemplo, você tentou executar um método private, uma IllegalAccessException é lançada; e outra exceção ocorre no caso de que o próprio método lance uma exceção, esta exceção vem então encapsulada dentro de uma InvocationTargetException. Caso você tenha mandado os métodos errados para o invoke, uma IllegalArgumentException é lançada.
Criando novos objetos
É muito comum, que, dado um objeto da classe Class, nós precisarmos de uma instância dessa classe. Java também permite isso, invocando os construtores de uma classe com os parâmetros desejados.

Se você quisesse chamar o construtor default de uma classe, isto é, o que não recebe nenhum parâmetro, basta você utiliza o método newInstance() da própria classe Class.
Alterando o valor dos campos
Outro uso da Reflection é para se alterar o valor dos campos de dados dos objetos. Esse nome pode ser achado pelo seu nome, via Reflection em um programa em execução e então ter o seu valor alterado. Veja no exemplo:

Usando arrays
Um último uso do Reflection em Java é a criação e manipulação de arrays. Em Java, arrays são uns tipos de dados especializados, e uma referência a uma array pode ser referenciado a uma referência do tipo Object. para ver como Reflection trabalha com arrays, veja a seguir:

Neste exemplo é criado um array de 10 objetos String e para a posição 5 do array ele seta uma instância de String.
Sumário
Java Reflection é muito útil pois ele suporta a recuperação das informações das classes e estruturas de dados pelo nome, e ainda permita a sua manipulação por um programa Java em execução. Essa é uma poderosa ferramente para desenvolvimento de solução muito genéricas e que não é encontrada em muitas outras tecnologias. Lembre-se que reflection é algo relativamente lento (melhoraram o desempenho no jdk1.4), e muito "error-prone" (sucetível a erro), então você deveria evitar usá-la, a não ser que realmente seja necessário.