Reflexão Marco Antonio Arquiteto de Software Novembro/2007
O que é Reflexão é geralmente utilizado por programas que precisam modificar o comportamento de uma aplicação em tempo de execução É um recurso avançado e deve ser usado apenas quando o desenvolvedor tem um grande conhecimento sobre os fundamentos da linguagem Por outro lado, reflexão é uma técnica poderosa que faz as aplicações executar operações que seriam impossíveis de outra maneira Uma aplicação pode usar recursos externos, criando objetos usando apenas o nome das classes
Limitações da reflexão Reflexão é um recurso poderoso, mas não pode ser usada de qualquer modo Se você puder executar uma operação sem reflexão é melhor evitá-la...
Overhead Reflexão envolve tipos que são definidos dinamicamente, dessa forma, Java não consegue fazer todas as otimizações de um código normal Operações com reflexão são sempre mais lentas que as operações normais Essas operações devem ser evitadas em código muito executado, por questões de performance
Segurança Reflexão requer permissões especiais que podem não estar disponíveis em ambientes seguros
Exposição Reflexão permite que você execute código privado, o que pode resultar em comportamento não esperado Código com reflexão acaba com sua abstração e pode ter comportamento diferente com a atualização da plataforma
Objetos dinâmicos O ponto inicial para reflexão é java.lang.Class Todas as demais classes estão no pacote java.lang.reflect
ClasseReflexiva package net.javabasico.reflexao; public class ClasseReflexiva { public void executaUmMetodo() { System.out.println("Executei um método"); }
TestaAReflexao package net.javabasico.testereflexao; 1. import java.lang.reflect.*; public class TestaAReflexao { public static void main(String[] args) { 2. try { 3. Class clazz = Class.forName("net.javabasico.reflexao.ClasseReflexiva"); 4. Object objeto = clazz.newInstance(); 5. Method m = clazz.getMethod("executaUmMetodo"); 6. m.invoke(objeto); 7. } catch (Exception e) { 8. e.printStackTrace(); }
Recuperando um método 1. Todas as classes que você vai usar estão nesse pacote 2. Para usar reflexão é necessário o try/catch para tratamento das exceções geradas Exemplo: você pode digitar o nome do método errado, o Eclipse não vai poder te ajudar 3. Cria um objeto do tipo Class chamado clazz (o nome poderia ser qualquer um) Vamos recuperar os métodos desse objeto através da reflexão
Cont. 4. Precisamos de um objeto do tipo Object para executar (invocar) o nosso método de exemplo 5. Recupera o método baseando-se em seu nome através da reflexão 6. Executa (invoca) o método 7. Fecha o tratamento de exceção 8. Imprime os erros, caso ocorram
ClasseReflexiva package net.javabasico.reflexao; public class ClasseReflexiva { public String umaString = "Esse é meu valor padrão"; public void executaUmMetodo() { System.out.println("Executei um método"); }
TestaAReflexao package net.javabasico.testereflexao; import java.lang.reflect.*; public class TestaAReflexao { public static void main(String[] args) { try { Class clazz = Class.forName("net.javabasico.reflexao.ClasseReflexiva"); Object objeto = clazz.newInstance(); // Method m = clazz.getMethod("executaUmMetodo"); // m.invoke(objeto); 1. Field atributo = clazz.getField("umaString"); 2. System.out.println(atributo.get(objeto)); } catch (Exception e) { e.printStackTrace(); }
Recuperando um atributo 1.Recupera o atributo pelo nome 2.Recupera e imprime o valor do atributo
ClasseReflexiva package net.javabasico.reflexao; public class ClasseReflexiva { public String umaString = "Esse é meu valor padrão"; public void executaUmMetodo() { System.out.println("Executei um método"); } public void executaOutroMetodo(String parametro) { System.out.println("O parâmetro é: " + parametro); }
TestaAReflexao package net.javabasico.testereflexao; import java.lang.reflect.*; public class TestaAReflexao { public static void main(String[] args) { try { Class clazz = Class.forName("net.javabasico.reflexao.ClasseReflexiva"); Object objeto = clazz.newInstance(); 1. Method m = clazz.getMethod("executaOutroMetodo", String.class); 2. m.invoke(objeto, "Marco Antonio"); } catch (Exception e) { e.printStackTrace(); }
Método com parâmetro 1.Recupera o método pelo nome, informando qual o tipo do parâmetro. No nosso caso, o parâmetro é uma String 2.Invoca o método passando o valor. Esse valor será utilizado pelo objeto
ClasseReflexiva package net.javabasico.reflexao; public class ClasseReflexiva { public String umaString = "Esse é meu valor padrão"; public void executaUmMetodo() { System.out.println("Executei um método"); } public void executaOutroMetodo(String parametro) { System.out.println("O parâmetro é: " + parametro); } public String recuperaUmValor() { return "Esse valor foi recuperado"; }
TestaAReflexao package net.javabasico.testereflexao; import java.lang.reflect.*; public class TestaAReflexao { public static void main(String[] args) { try { Class clazz = Class.forName("net.javabasico.reflexao.ClasseReflexiva"); Object objeto = clazz.newInstance(); 1. Method m = clazz.getMethod("recuperaUmValor"); 2. String s = (String) m.invoke(objeto); 3. System.out.println(s); } catch (Exception e) { e.printStackTrace(); }
Recuperando um valor 1.Recupera o método pelo nome 2.Invoca o método. O sublinhado é chamado de cast, ou seja, conversão, pois o método pode retornar uma String, um Double, ou qualquer outra classe java 3.Imprime o valor de retorno do método
Exercícios Utilizando reflexão, execute todos os métodos da classe ContaCorrente
Alguns métodos utilitários package net.javabasico.testereflexao; import java.lang.reflect.*; public class TestaAReflexao { public static void main(String[] args) { try { Class clazz = Class.forName("net.javabasico.reflexao.ClasseReflexiva"); 1. System.out.println(clazz.getPackage()); 2. for (Method m : clazz.getMethods()) { 3. System.out.println(m.getName()); } 4. for (Field f : clazz.getFields()) { System.out.println(f.getName()); } } catch (Exception e) { e.printStackTrace(); }
Utilitários 1.Imprime o pacote da classe 2.Estrutura conhecida como forEach (para cada) Exemplo: para cada método de clazz, faça algo, no nosso caso, imprima 3.Imprime o nome de cada um dos métodos da classe 4.Imprime cada um dos atributos da classe
Dúvidas