Olá povo, voltei aqui só para fazer um post rápido, dessa vez um mais técnico, vou mostrar como acessar um método privado usando o lindo reflection, resolvi fazer esse post para quebrar as pernas do Eduardo definitivamente.
Para quem não acompanha o nosso blog vou explicar… o Eduardo começou a escrever uma serie de post sobre POO (Orientação a Objetos em Cinco Minutos e Orientação a Objetos em Cinco Minutos parte 2) sendo que nesse segundo ele me desafiou a burlar a regra de negocio da classe dele… se quiser entender melhor leia os posts do Eduardo….
Então vamos começar…
Se você é programador de verdade é curioso e já deve ter perguntando: Como o Hibernate, Struts e Cia fazem para acessar nossas classes sem as conhecer? Como acessam nossos atributos e métodos privados…
Para entender isso direito e realmente ser um programador Java e não um framework boy você deve conhecer um recurso não muito novo do Java mas muito inteligente chamado reflection. Ele existe dês da versão 1.1 do Java e nada mais é que uma API para obter e modificar em tempo de execução informações sobre um objeto, com ele você pode criar um objeto simplesmente escrevendo o Classname dele, listar e executar métodos sem precisar saber o nome dele dentre inúmeras outras funcionalidades legais…
Para esse primeiro post sobre reflection do grupo HAW vou ensinar a modificar o valor de um atributo privado e para isso vou usar as classes dos artigos do Eduardo(Orientação a Objetos em Cinco Minutos e Orientação a Objetos em Cinco Minutos parte 2)
No post do Eduardo ele criou uma classe chamada Carro que deveria decolar caso a velocidadeMaxima fosse igual a velocidadeAtual, só que para mudar de velocidadeAtual o usuario da classe deveria disparar um metodo chamado acelerar e o mesmo seria o responsável de mudar o atributo pois ele é um atributo privado, como você sabe a gente faz isso para poder executar uma regra de negocio toda vez que o atributo for modificado, no caso o Eduardo alterara a velocidade de acordo com a marcha em que o carro esta… bom… isso é matéria do artigo do Eduardo é só você lê para entender…
Então para poder fazer o carro decola quando a atributo não era privado ( no primeiro artigo) eu acessei diretamente e coloquei o valor dele na munheca como abaixo:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class FabricaDeCarrosDoWenderson { public static void main(String[] args) { Carro carro1 = new Carro(); carro1.nome = "Carro Alegórico"; carro1.marca = "FastWend"; carro1.velocidadeMaxima = 1000; carro1.quantidadeDeMarchas = 5; carro1.velocidadeAtual=1000; carro1.decola(); } } |
Mas como no segundo artigo ele colocou o atributo como privado(e pensou que tava tudo resolvido), então vamos usar o Reflaction para quebrar as pernas do Eduardo, abaixo o código e depois a explicação:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
import java.lang.reflect.*; public class FabricaDeCarrosDoWenderson { public static void main(String[] args) { Carro carro1 = new Carro(); carro1.nome = "Carro Alegórico"; carro1.marca = "FastWend"; carro1.velocidadeMaxima = 1000; carro1.quantidadeDeMarchas = 5; // carro1.velocidadeAtual=1000; try { Class objetoCarro = Class.forName("eduardo.Carro"); Field atributoVelocidadeAtual = objetoCarro .getDeclaredField("velocidadeAtual"); atributoVelocidadeAtual.setAccessible(true); atributoVelocidadeAtual.setDouble(carro1, 1000); } catch (Throwable erro) { System.err.println(erro); } carro1.decola(); } } |
Quando agente trabalha com reflection precisamos colocar um bloco para tratamento de erro, (futuramente o grupo haw irá fazer uma artigo sobre isso), pois é um trabalho extremamente passível a erro (abaixo explico o porque), na linha 14 agente cria o objeto objetoCarro que servirá como um “objeto de apoio” contendo toda a assinatura da classe Carro.
Passando o forName da classe Carro para o método abstrato da classe Class, ele cospe o objeto desejato para assim podermos colocar no objetoCarro.
Logo depois temos que criar um objeto do tipo Field que será o responsável por controlar o atributo ao qual queremos acessar, para isso devemos usar o método getDeclaredField que pertence a classe Class, esse método é o responsável por procurar na assinatura da classe um atributo com o nome exatamente igual ao passado via parâmetro.
Com o campo na Mao podemos trabalhar em cima dele livremente, alterando quase tudo dele, para esse exemplo estamos mudando a acessibilidade dele para acessível, é como se colocássemos ele como publico ao invés de privado, sem isso não conseguiríamos manipular seu valor
Na linha de baixo setamos o valor 1000 do campo no objeto carro1 note que usamos o método para setar Double tem um para cada tipo de objeto, terminando assim a maracutaia de mudar o valor de um atributo privado fora da classee quebrando as pernas do Eduardo mais uma vez… (wenderson 2 X Eduardo 0)
Considerações finais…
Primeiro quero falar que não devemos usar esse recurso da maneira que eu apresentei, pois matamos as regras de negocio da classe, se quisermos fazer isso devemos usar um javabean com métodos Gets e Sets e ainda que por estarmos em tempo de execução o controle do erro fica muito complicado, pois o compilador só vai perceber que a string que você informou trata-se de uma classe que não existe somente depois de tentar achar-la no contexto e não encontrá-la, o mesmo para a criação do Field, essa técnica é totalmente passível de erro por isso é até obrigatória estar em um bloco de tratamento de erro (ou em um throws).
A pedido do Gabriel vou informar que não quebrei a perna do Eduardo é apenas uma figura de linguagem e uma brincadeira que usamos para aprender (nenhum animal foi maltratado nessa elaboração do post)
Futuramente farei uma serie de post com um exemplo real de uso de reflection juntamente com criação de annotations assim que acabar a serie do RUP(Rica Utopia Pobre) até lá.
Muito bom, veja a API Mirror, ajuda muito
http://projetos.vidageek.net/mirror-pt/mirror/