Conversando com uns amigos da pós-graduação, surgiu a pergunta: O que é reflection? Sabiamos a resposta, mas sabe quando você fica olhando um para cara do outro e acaba falando: “ah é díficil de explicar”. Então essa foi a motivação para esse post.
O que é reflection? reflection é considerado lento? vou “quebrar” o encapsulamento?
Reflection é geralmente utilizando para oferecer a opção da aplicação instanciar classes, invocar métodos e acessar atributos a partir de strings, como o nome do método que se quer invocar, passadas como parametros, fazendo com que a aplicação execute fluxos de controle mais dinâmicos e em tempo de execução.
Frameworks como o JSF e o Struts utilizam reflection para atribuir valores do request dentro das propriedades de um java bean.
Na verdade reflection é bem mais simples do que se imagina, já que ele trabalha na “execução dinâmica” de coisas triviais para os desenvolvedores: classes, métodos, atributos e etc. Basicamente o código consiste em fazer um cast de uma chamada Class.newInstance usado para criar novos objetos para a classe/interface que se deseja utilizar.
A API de Criação de Objetos disponibiliza um método static para programaticamente instânciar classes em tempo de execução fornecendo apenas o nome da classe. Basicamente utilizando Class.forName(“net.valdemarjr.blog.Classe”). Esse método é o mais comum para recuperar a instância, mas não é o único método, possuindo também Class.forName(String name, boolean initialize, ClassLoader loader).
Class reflection = Class.forName("net.valdemarjr.blog.Classe"); |
Para Invocar métodos é obter o Class e dele você pode iterar entre o array de métodos da classe ou através da assinatura do método. E a invocação do método é através de Method.invoke();
Method[] methods = classe.getMethods(); |
Assim como classes e métodos podem ser acessados em tempo de execução acessar atributos não poderia ficar de fora. Atributos podem ser lidos e escritos em tempo de execução chamando os métodos Field.get e Field.set, classe que é recuperada apartir da instância criada Class.newInstance().
Field field = classe.getField("atributo"); |
Um detalhe importante é que todas a regras de visibilidade(protected, default, private e etc) ainda são validas, então não adianta tentar acessar um atributo private de uma outra classe, por exemplo, você receberá um java.lang.NoSuchFieldException.
Lógico que reflection não é apenas isso, tanto que tem um livro falando só sobre reflection. Bom fica a dica aí.
3 comentários:
Olá,
talvez você se interesse por esse projeto, que facilita o trabalho com a API de Reflection do Java.
http://projetos.vidageek.net/mirror/mirror/
Ola Valdemar,
Reflection é realmente bem interessante e bem ùtil.
Os exemplos de còdigo que vc mostra são bem claros e diretos. Entretanto, a regra de visibilidade pode ser burlada com o método Field.setAccessible (exceto se vc proibir isso com java security policies), como no exemplo que coloco abaixo. Na verdade isso não vai mudar o bytecode da classe, e o campo continuarà private. O que ele faz é alterar a acessibilidade daquela instância de Field. Caso o set seja feito novamente, mas sem efetuar o setAccessible, a exceção NoSuchFieldException serà levantada.
Segue o exemplo:
...
Test t = new Test();
Field f = t.getClass().getDeclaredField("x");
f.setAccessible(true);
/* o set vai funcionar graças à linha anterior */
f.set(t, new Integer(1));
/* abaixo, recupera-se outra instancia de field */
f = t.getClass().getDeclaredField("x");
/* tentativa de set sem mudar acessibilidade var gerar erro */
f.set(t, new Integer(1));
...
/*A classezinha de exemplo*/
class Test {
private int x;
}
Saudações,
Kiev
@Jonas Utilizei a lib que você passou, realmente muito boa, só de não ficar lançando aquele monte de Exception, já deixa o código mais limpo. Parabéns pelo projeto, vou indicar no meu trabalho.
Postar um comentário