Este artigo descreve detalhadamente o mecanismo de reflexão do Java na forma de exemplos, que é uma habilidade importante na programação Java. Compartilhe com todos para sua referência. A análise específica é a seguinte:
Em primeiro lugar, o Reflection é um dos recursos da linguagem de desenvolvimento de programas Java. Ele permite que o programa Java em execução verifique a si mesmo, ou "autoauditoria", e opere diretamente as propriedades internas do programa . Por exemplo, use-o para obter o nome de cada membro em uma classe Java e exibi-lo. Esse recurso do Java pode não ser muito usado em aplicações práticas, mas esse recurso não existe em outras linguagens de programação. Por exemplo, em Pascal, C ou C++ não há como obter informações sobre definições de funções no programa.
JavaBean é uma das aplicações práticas de reflexão, que permite que algumas ferramentas operem visualmente componentes de software. Essas ferramentas carregam e obtêm dinamicamente as propriedades dos componentes Java (classes) por meio de reflexão.
1. Um exemplo simples
Considere o seguinte exemplo simples e vamos ver como funciona a reflexão.
import java.lang.reflect.*; public class DumpMethods { public static void main(String args[]) { try { Class c = Class.forName("java.util.Stack"); (); for (int i = 0; i < m.length; i++) System.out.println(m[i].toString() } catch (Throwable). e){ System.err.println(e);
Sua saída de resultado é:
java sincronizado público.lang.Object java.util.Stack.pop() java público.lang.Object java.util.Stack.push (java.lang.Object) público booleano java.util.Stack.empty() java sincronizado público .lang.Object java.util.Stack.peek() público sincronizado int java.util.Stack.search(java.lang.Object)
Isso lista os nomes dos métodos da classe java.util.Stack junto com seus qualificadores e tipos de retorno.
Este programa usa Class.forName para carregar a classe especificada e, em seguida, chama getDeclaredMethods para obter a lista de métodos definidos na classe. java.lang.reflect.Methods é uma classe usada para descrever um único método em uma classe.
2. Comece a usar o Reflexo
Classes para reflexão, como Method, podem ser encontradas no pacote java.lang.relfect. Existem três etapas que você deve seguir ao usar essas classes: A primeira etapa é obter o objeto java.lang.Class da classe na qual deseja operar. Em um programa Java em execução, a classe java.lang.Class é usada para descrever classes, interfaces, etc.
A seguir está uma das maneiras de obter um objeto Class:
Classe c = Class.forName("java.lang.String");
Esta instrução obtém um objeto de classe da classe String. Existe outra maneira, como a seguinte afirmação:
Classe c = int.class; ou Classe c = Integer.TYPE;
Eles obtêm informações de classe para tipos básicos. O último método acessa o campo TYPE predefinido na classe de encapsulamento de tipo básico (como Integer).
A segunda etapa é chamar um método como getDeclaredMethods para obter uma lista de todos os métodos definidos na classe.
Uma vez obtidas essas informações, você pode prosseguir para a terceira etapa - usar a API de reflexão para operar essas informações, como o seguinte código:
Classe c = Class.forName("java.lang.String"); Método m[] = c.getDeclaredMethods();
Ele imprimirá textualmente o protótipo do primeiro método definido em String.
No exemplo a seguir, essas três etapas ilustram o uso da reflexão para uma aplicação específica.
Simular o operador instanceof
Após obter as informações da classe, geralmente o próximo passo é resolver algumas questões básicas sobre o objeto Classe. Por exemplo, o método Class.isInstance pode ser usado para simular o operador instanceof:
class S { } public class IsInstance { public static void main(String args[]) { try { Class cls = Class.forName("S"); .println(b1); booleano b2 = cls.isInstance(new S()); (Arremessável e) { System.err.println(e);
Neste exemplo, um objeto Class da classe S é criado e, em seguida, alguns objetos são verificados para ver se são instâncias de S. Integer(37) não é, mas new S() é.
3. Encontre o método da classe
Descobrir quais métodos são definidos em uma classe é um uso de reflexão muito valioso e básico. O código a seguir implementa esse uso:
import java.lang.reflect.*; public class Method1 { private int f1(Object p, int x) throws NullPointerException { if (p == null) throw new NullPointerException() return x; []) { try { Classe cls = Class.forName("Método1"); Método metlist[] = cls.getDeclaredMethods(); for (int i = 0; i < metlist.length; i++) { Método m = metlist[i]; class = " + m.getDeclaringClass()); Classe pvec[] = m.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Classe evec[] = m.getExceptionTypes(); out.println("exc #" + j + " " + evec[j]); System.out.println("tipo de retorno = " + m.getReturnType()); System.out.println("-----"); catch (Throwable e) { System.err.println(e);
Este programa primeiro obtém a descrição da classe method1 e, em seguida, chama getDeclaredMethods para obter uma série de objetos Method, que descrevem cada método definido na classe, incluindo métodos públicos, métodos protegidos, métodos de pacote e métodos privados. Se você usar getMethods em vez de getDeclaredMethods em seu programa, também poderá obter informações sobre cada método herdado.
Depois de obter a lista de objetos Método, não é difícil exibir os tipos de parâmetros, tipos de exceções, tipos de valores de retorno, etc. Quer esses tipos sejam tipos primitivos ou tipos de classe, eles podem ser dados em ordem pelos objetos que descrevem a classe.
Os resultados de saída são os seguintes:
nome = f1 classe decl = classe método1 parâmetro #0 classe java.lang.Object parâmetro #1 int exc #0 classe java.lang.NullPointerException tipo de retorno = int-----name = classe decl principal = classe método1 parâmetro #0 classe [Ljava.lang.String; tipo de retorno = void
4. Obtenha informações do construtor
O uso de obtenção do construtor de classe é semelhante ao uso do método de obtenção acima, como:
import java.lang.reflect.*;public class Construtor1 { public Construtor1() { } protected Construtor1(int i, double d) { } public static void main(String args[]) { try { Class cls = Class.forName( "Construtor1"); Construtor ctorlist[] = cls.getDeclaredConstructors(); i++) { Construtor ct = ctorlist[i]; System.out.println("nome = " + ct.getName()); [] = ct.getParameterTypes(); for (int j = 0; j < pvec.length; j++) System.out.println("param #" + j + " " + pvec[j]); Classe evec[] = ct.getExceptionTypes(); for (int j = 0; j < evec.length; j++) System.out.println("exc #" + j + " " + evec[j]); System.out.println("-----"); }
Neste exemplo, nenhuma informação sobre o tipo de retorno pode ser obtida, pois o construtor não possui um tipo de retorno.
O resultado da execução deste programa é:
nome = Construtor1decl classe = classe Construtor1param #0 intparam #1 duplo-----name = Construtor1decl classe = classe Construtor1-----
5. Obtenha os campos (domínios) da classe
Também é possível descobrir quais campos de dados estão definidos em uma classe, como faz o código a seguir:
import java.lang.reflect.*; public class Field1 { private double d; try { Class cls = Class. forName("Campo1"); Campo fieldlist[] = cls.getDeclaredFields(); for (int i = 0; i < fieldlist.length; i++) { Campo fld = 0; fieldlist[i]; System.out.println("nome = " + fld.getName()); System.out.println("decl class = " + fld.getDeclaringClass()); = " + fld.getType()); int mod = fld.getModifiers(); System.out.println("modifiers = " + Modifier.toString(mod)); System.out.println("-----"); catch (Throwable e) { System.err.println(e);
Este exemplo é muito semelhante ao anterior. Neste exemplo, um novo modificador é usado, que também é uma classe de reflexão e é usado para descrever os modificadores dos membros do campo, como "private int". Os próprios modificadores são descritos por números inteiros, e Modifier.toString é usado para retornar as descrições das strings na ordem "oficial" (por exemplo, "estático" antes de "final"). A saída deste programa é:
nome = ddecl classe = classe Field1type = doublemodifiers = private-----name = idecl classe = classe Field1type = intmodifiers = public static final-----name = sdecl class = class Field1type = classe java.lang.Stringmodifiers = - ----
Assim como acontece com o método get, ao obter campos, você também pode obter apenas as informações do campo declaradas na classe atual (getDeclaredFields) ou também pode obter os campos definidos na classe pai (getFields).
6. Execute o método de acordo com seu nome
Neste ponto do texto, os exemplos dados estão todos relacionados a como obter informações de classe. Também podemos usar a reflexão para fazer outras coisas, como executar um método com um nome especificado. O exemplo a seguir demonstra esta operação:
import java.lang.reflect.*; public class Método2 { public int add(int a, int b) { return a + b; public static void main(String args[]) { try { Class cls = Class.forName( "Método2"); Classe partypes[] = new Class[2]; cls.getMethod("adicionar", partypes); Método2 methobj = novo Objeto arglist[] = new Arglist[0] = new Integer(37); ); Objeto retobj = meth.invoke(methobj, lista de argumentos); retobj; System.out.println(retval.intValue() } catch (Throwable e) { System.err.println(e);
Se um programa sabe apenas que um determinado método precisa ser executado em algum lugar durante a execução, e o nome desse método é especificado durante a execução do programa (por exemplo, isso é feito no ambiente de desenvolvimento JavaBean), então o programa acima Demonstrado como fazer isso.
No exemplo acima, getMethod é usado para encontrar um método chamado add que possui dois parâmetros inteiros. Depois de encontrar o método e criar o objeto Method correspondente, execute-o na instância correta do objeto. Ao executar este método, você precisa fornecer uma lista de parâmetros, que no exemplo acima são dois objetos Integer que envolvem os inteiros 37 e 47 respectivamente. O método de execução retorna um objeto Integer, que encapsula o valor de retorno 84.
7. Crie novos objetos
Para construtores, você não pode proceder como a execução de métodos, porque executar um construtor significa criar um novo objeto (para ser mais preciso, o processo de criação de um objeto inclui a alocação de memória e a construção do objeto). Portanto, o exemplo mais semelhante ao exemplo acima é o seguinte:
importar java.lang.reflect.*; public class Construtor2 { public Construtor2() { } public Construtor2(int a, int b) { System.out.println("a = " + a + " b = " + b); } public static void main(String args[]) { try { Class cls = Class.forName("Construtor2"); partypes[0] = Integer.TYPE; partypes[1] = Integer.TYPE; Construtor ct = cls.getConstructor(partypes); arglist[1] = new Integer(47); Objeto retobj = ct.newInstance(arglist } catch); (Arremessável e) { System.err.println(e);
Encontre o construtor correspondente com base nos tipos de parâmetros especificados e execute-o para criar uma nova instância de objeto. Usar essa abordagem permite criar objetos dinamicamente enquanto o programa está em execução, e não em tempo de compilação, o que é muito valioso.
8. Altere o valor de um campo (domínio)
Outro uso da reflexão é alterar os valores dos campos de dados do objeto. O Reflection pode encontrar os campos de um objeto por nome em um programa em execução e alterá-lo.
import java.lang.reflect.*; public class Field2 { public double d; public static void main(String args[]) { try { Class cls = Class.forName("Field2"); d"); Campo2 f2obj = new Campo2(); System.out.println("d = " + f2obj.d); fld.setDouble(f2obj, 12.34); System.out.println("d = " + f2obj.d } catch (Throwable e) { System.err.println(e);
Neste exemplo, o valor do campo d é alterado para 12,34.
9. Use matrizes
O uso final da reflexão apresentado neste artigo é a criação de matrizes de operandos. Array é um tipo de classe especial na linguagem Java e uma referência de array pode ser atribuída a uma referência de objeto. Observe o exemplo a seguir para ver como funcionam os arrays:
import java.lang.reflect.*; public class Array1 { public static void main(String args[]) { try { Class cls = Class.forName("java.lang.String"); , 10); Array.set(arr, 5, "este é um teste"); String s = (String) Array.get(arr, 5); System.out.println(s); catch (Throwable e) { System.err.println(e);
No exemplo, um array String de comprimento de 10 unidades é criado, um valor é atribuído à string na 5ª posição e, finalmente, a string é obtida do array e impressa.
O código a seguir fornece um exemplo mais complexo:
import java.lang.reflect.*; public class Array2 { public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; TIPO, dims); Objeto arrobj = Array.get(arr, 3); arrobj.getClass().getComponentType(); System.out.println(cls); (int[][][])arr;System.out.println(arrcast[3][5][10]);
No exemplo, uma matriz inteira de 5 x 10 x 15 é criada e o elemento em [3][5][10] recebe o valor 37. Observe que arrays multidimensionais são na verdade arrays de arrays, por exemplo, após o primeiro Array.get, arrobj é um array 10 x 15. Em seguida, pegue um dos elementos, ou seja, um array com comprimento 15, e use Array.setInt para atribuir um valor ao seu 10º elemento.
Observe que o tipo do array quando criado é dinâmico e seu tipo não é conhecido em tempo de compilação .
Acredito que o que este artigo descreve tem certo valor de referência para o aprendizado de programação Java de todos.