De que se trata o artigo: Neste artigo veremos como uma aplicação pode ler e alterar seu comportamento em tempo de execução. Em seguida, vamos colocar essa técnica em prática e criar uma aplicação que pode ter suas funcionalidades ampliadas através do uso de plugins.


Para que serve:
Algumas vezes precisamos descobrir informações de objetos e classes em tempo de execução, ou até mesmo criar uma instância de uma classe, tendo em mãos somente o seu nome. Em situações como estas, entra em cena a reflexão.

Em que situação o tema útil: Um detalhe interessante da linguagem Java é que muitas das ferramentas construídas para trabalhar com ela foram desenvolvidas utilizando a própria linguagem. Essas ferramentas precisam ser dinâmicas e flexíveis, interagindo com o código que está sendo escrito. Quando nossa aplicação precisa acessar classes que não fazem parte dela diretamente, ela utiliza a reflexão, que é o mesmo recurso utilizado por essas ferramentas.

Uma das características mais interessantes e poderosas da tecnologia Java é a reflexão. Ela representa a capacidade que um programa possui de observar e modificar sua estrutura e comportamento em tempo de execução. Reflexão, ou Reflection, como também é conhecida, é uma API que permite a aplicações executarem operações que, de outra forma, seriam muito complicadas. Ela é usada para:

  • Estender funcionalidades: Podemos criar pontos de extensão em nossas aplicações para que as mesmas possam ter suas funcionalidades expandidas;
  • Manipulação de objetos em ambientes de desenvolvimento visual: Esses ambientes fazem parte dos IDEs (Ambientes de Desenvolvimento Integrado) e são conhecidos também como Editores Visuais (VE – Visual Editor). Sua principal função é facilitar a vida do programador, permitindo que objetos da interface com o usuário (botões, caixas de texto, painéis, etc.) sejam inseridos e manipulados em tempo de projeto, ou seja, enquanto a aplicação está sendo desenvolvida. Um dos recursos que é largamente utilizado para essa manipulação é a reflexão;
  • Criação de proxies dinâmicos: Proxy é um padrão de projeto onde, em linhas gerais, um objeto pode substituir outro. Usando a reflexão esses objetos podem ser criados dinamicamente. Proxies dinâmicos podem ser usados para os mais diversos fins, como conexões com bancos de dados, controle de transações e interceptadores de métodos (AOP).

AOP ou Aspect-Oriented Programming é um paradigma de desenvolvimento que permite aos programadores separar e organizar o código de acordo com a sua importância para a aplicação (ver Links no final do artigo).

O que veremos no nosso artigo é uma introdução a API de Reflexão da linguagem Java, começando pelos seus princípios básicos e concluindo com um exemplo que nos mostrará o seu uso no dia a dia de um desenvolvedor.

Padrões de projeto: Em linhas gerais, eles descrevem soluções para problemas recorrentes em desenvolvimento de software. Os mais conhecidos são os padrões GoF, que são divididos em três categorias:Padrões de criação, estruturais e comportamentais.

Princípios básicos de reflexão

Em Java, toda variável é uma referência ou um tipo primitivo. Os tipos primitivos se limitam a: byte, short, int, long, float, double, char e boolean. As referências incluem as classes, interfaces, enums e arrays.

Lembre-se: Mesmo quando o array é de tipos primitivos, o array em si é uma referência, apesar de cada um de seus elementos separadamente ser primitivo.

A forma como os projetistas da linguagem Java encontraram para organizar as classes foram os pacotes. A grosso modo, podemos comparar os pacotes a diretórios que armazenam as classes. O pacote java.lang é quem provê as classes fundamentais da linguagem. Classes como Integer, String e System estão nesse pacote. É nele também que vamos encontrar Class, uma classe que representa os tipos de objetos que estão rodando sob a máquina virtual. Outro pacote que será importante para nós é o java.lang.reflect. Nele encontram-se as classes e interfaces da API de Reflexão. Para cada tipo de objeto, a máquina virtual cria uma instância imutável de java.lang.Class, a qual provê métodos para examinar as propriedades do objeto em tempo de execução, incluindo seus atributos e informações de tipo.

Objetos imutáveis: Como o próprio nome diz, são objetos que, uma vez criados não podem mais ser alterados. O melhor exemplo são os objetos da classe String. Uma vez criada uma referência para um objeto da classe String, a mesma não pode mais ser alterada, é imutável. Isso explica o motivo do código:


String str = "java";
str.toUpperCase();
System.out.println(str); 

Imprimir "java" ao invés de "JAVA". A chamada a str.toUpperCase() cria uma nova String com o valor "JAVA", e não altera o valor de str como poderíamos pensar a princípio.

Tomando como base a Listagem 1, poderíamos descobrir que a classe Pessoa possui o atributo nome, um construtor sem parâmetros e o método andar(). Usando a referência a Class, também poderíamos criar novas instâncias da classe Pessoa. Mais adiante, veremos como usar esse recurso. As classes do pacote java.lang.reflect não possuem um construtor público, ou seja, não podemos usar o operador new para instanciarmos objetos. Dessa forma, somente conseguiremos referências para objetos dessas classes através de Class. Sendo assim, o primeiro passo para trabalharmos com reflexão é obtermos uma instância de java.lang.Class. Podemos obter esta instância de várias formas: através de uma referência, através do tipo da classe, ou de uma String contendo o nome da classe. Para exemplificarmos esse recurso, vamos criar as classes das Listagens 1 e 2.

...

Quer ler esse conteúdo completo? Tenha acesso completo