type - why use reflection in java




O que é reflexão e por que é útil? (14)

Reflection é a capacidade de uma linguagem de inspecionar e chamar dinamicamente classes, métodos, atributos, etc. em tempo de execução.

Por exemplo, todos os objetos em Java têm o método getClass() , que permite determinar a classe do objeto mesmo que você não o saiba em tempo de compilação (por exemplo, se você o declarou como um Object ) - isso pode parecer trivial, mas a reflexão não é possível em linguagens menos dinâmicas, como C++ . Usos mais avançados permitem listar e chamar métodos, construtores etc.

A reflexão é importante, pois permite que você escreva programas que não precisam "saber" tudo em tempo de compilação, tornando-os mais dinâmicos, já que podem ser vinculados em tempo de execução. O código pode ser escrito em interfaces conhecidas, mas as classes reais a serem usadas podem ser instanciadas usando a reflexão dos arquivos de configuração.

Muitas estruturas modernas usam a reflexão extensivamente por esse mesmo motivo. A maioria das outras linguagens modernas também usa a reflexão, e em linguagens de script (como o Python) elas são ainda mais integradas, já que parece mais natural dentro do modelo geral de programação dessas linguagens.

O que é reflexão e por que é útil?

Estou particularmente interessado em Java, mas presumo que os princípios sejam os mesmos em qualquer idioma.


A reflexão é deixar o objeto ver sua aparência. Este argumento parece não ter nada a ver com reflexão. Na verdade, essa é a capacidade de "autoidentificação".

A própria reflexão é uma palavra para essas linguagens que não possuem a capacidade de autoconhecimento e auto-percepção como Java e C #. Como eles não têm a capacidade de autoconhecimento, quando queremos observar como é, precisamos ter outra coisa para refletir sobre como ela se parece. Excelentes linguagens dinâmicas como Ruby e Python podem perceber o próprio reflexo sem a ajuda de outros indivíduos. Podemos dizer que o objeto de Java não pode perceber como ele se parece sem um espelho, que é um objeto da classe de reflexão, mas um objeto em Python pode percebê-lo sem um espelho. Então é por isso que precisamos de reflexão em Java.


Da page documentação java

java.lang.reflect pacote java.lang.reflect fornece classes e interfaces para obter informações reflexivas sobre classes e objetos. O Reflection permite acesso programático a informações sobre os campos, métodos e construtores de classes carregadas e o uso de campos, métodos e construtores refletidos para operar em suas contrapartes subjacentes, dentro de restrições de segurança.

AccessibleObject permite a supressão de verificações de acesso se o ReflectPermission necessário estiver disponível.

As classes neste pacote, junto com java.lang.Class acomodam aplicativos como depuradores, intérpretes, inspetores de objetos, navegadores de classe e serviços como Object Serialization e JavaBeans que precisam de acesso aos membros públicos de um objeto de destino classe de tempo de execução) ou os membros declarados por uma determinada classe

Inclui a seguinte funcionalidade.

  1. Obtenção de objetos de classe,
  2. Examinando propriedades de uma classe (campos, métodos, construtores),
  3. Configurando e obtendo valores de campo,
  4. Invocando métodos,
  5. Criando novas instâncias de objetos.

Dê uma olhada neste link de documentation para os métodos expostos pela classe Class .

A partir deste article (por Dennis Sosnoski, presidente da Sosnoski Software Solutions, Inc) e este article (pdf de explorações de segurança):

Eu posso ver desvantagens consideráveis ​​do que usar o Reflection

Usuário de Reflexão:

  1. Ele fornece uma maneira muito versátil de vincular dinamicamente os componentes do programa
  2. É útil para criar bibliotecas que funcionam com objetos de formas muito gerais

Desvantagens da Reflexão:

  1. A reflexão é muito mais lenta que o código direto quando usada para acesso a campos e métodos.
  2. Pode obscurecer o que realmente está acontecendo dentro do seu código
  3. Ele ignora o código-fonte pode criar problemas de manutenção
  4. O código de reflexão também é mais complexo que o código direto correspondente
  5. Permite violação das principais restrições de segurança Java, como proteção de acesso a dados e segurança de tipos

Abusos gerais:

  1. Carregamento de classes restritas
  2. Obtendo referências a construtores, métodos ou campos de uma classe restrita,
  3. Criação de novas instâncias de objetos, invocação de métodos, obtenção ou configuração de valores de campo de uma classe restrita.

Dê uma olhada nesta questão do SE sobre o recurso de abuso de reflexão:

Como leio um campo privado em Java?

Resumo:

O uso inseguro de suas funções conduzidas dentro de um código de sistema também pode levar facilmente ao comprometimento de um modo de segurança Java . Então use esse recurso com moderação


Eu só quero adicionar algum ponto a tudo o que foi listado.

Com o Reflection API, você pode escrever o toString() universal para qualquer objeto.

É útil na depuração.

Aqui está um exemplo:

class ObjectAnalyzer {

   private ArrayList<Object> visited = new ArrayList<Object>();

   /**
    * Converts an object to a string representation that lists all fields.
    * @param obj an object
    * @return a string with the object's class name and all field names and
    * values
    */
   public String toString(Object obj) {
      if (obj == null) return "null";
      if (visited.contains(obj)) return "...";
      visited.add(obj);
      Class cl = obj.getClass();
      if (cl == String.class) return (String) obj;
      if (cl.isArray()) {
         String r = cl.getComponentType() + "[]{";
         for (int i = 0; i < Array.getLength(obj); i++) {
            if (i > 0) r += ",";
            Object val = Array.get(obj, i);
            if (cl.getComponentType().isPrimitive()) r += val;
            else r += toString(val);
         }
         return r + "}";
      }

      String r = cl.getName();
      // inspect the fields of this class and all superclasses
      do {
         r += "[";
         Field[] fields = cl.getDeclaredFields();
         AccessibleObject.setAccessible(fields, true);
         // get the names and values of all fields
         for (Field f : fields) {
            if (!Modifier.isStatic(f.getModifiers())) {
               if (!r.endsWith("[")) r += ",";
               r += f.getName() + "=";
               try {
                  Class t = f.getType();
                  Object val = f.get(obj);
                  if (t.isPrimitive()) r += val;
                  else r += toString(val);
               } catch (Exception e) {
                  e.printStackTrace();
               }
            }
         }
         r += "]";
         cl = cl.getSuperclass();
      } while (cl != null);

      return r;
   }    
}

Nem toda linguagem suporta reflexão, mas os princípios são geralmente os mesmos em linguagens que a suportam.

Reflexão é a capacidade de "refletir" sobre a estrutura do seu programa. Ou mais concreto. Para examinar os objetos e classes que você possui e obter programaticamente informações sobre os métodos, campos e interfaces que eles implementam. Você também pode ver coisas como anotações.

É útil em muitas situações. Em todo lugar você quer poder conectar dinamicamente classes em seu código. Muitos mapeadores relacionais de objetos usam a reflexão para poder instanciar objetos de bancos de dados sem saber com antecedência quais objetos eles vão usar. As arquiteturas de plug-in são outro local onde a reflexão é útil. Ser capaz de carregar dinamicamente o código e determinar se existem tipos lá que implementam a interface correta para usar como um plugin é importante nessas situações.


O Java Reflection é bastante poderoso e pode ser muito útil. O Java Reflection possibilita inspecionar classes, interfaces, campos e métodos em tempo de execução, sem conhecer os nomes das classes, métodos etc. em tempo de compilação. Também é possível instanciar novos objetos, invocar métodos e obter / definir valores de campo usando reflexão.

Um rápido exemplo do Java Reflection para mostrar como é o reflexo:

Method[] methods = MyObject.class.getMethods();

    for(Method method : methods){
        System.out.println("method = " + method.getName());
    }

Este exemplo obtém o objeto Class da classe chamada MyObject. Usando o objeto de classe, o exemplo obtém uma lista dos métodos dessa classe, repete os métodos e imprime seus nomes.

Exatamente como tudo isso funciona é explicado aqui

Edit : Após quase 1 ano eu estou editando esta resposta enquanto ao ler sobre reflexão eu tenho mais alguns usos de Reflection.

  • Spring usa configuração de beans como:


<bean id="someID" class="com.example.Foo">
    <property name="someField" value="someValue" />
</bean>

Quando o contexto Spring processar este elemento <bean>, ele usará Class.forName (String) com o argumento "com.example.Foo" para instanciar essa classe.

Em seguida, ele usará novamente a reflexão para obter o setter apropriado para o elemento <property> e definir seu valor para o valor especificado.

  • O Junit usa o Reflection especialmente para testar métodos privados / protegidos.

Para métodos privados,

Method method = targetClass.getDeclaredMethod(methodName, argClasses);
method.setAccessible(true);
return method.invoke(targetObject, argObjects);

Para campos privados,

Field field = targetClass.getDeclaredField(fieldName);
field.setAccessible(true);
field.set(object, value);

O Reflection oferece a capacidade de escrever mais códigos genéricos. Ele permite que você crie um objeto em tempo de execução e chame seu método em tempo de execução. Por isso, o programa pode ser altamente parametrizado. Também permite introspectar o objeto e a classe para detectar suas variáveis ​​e métodos expostos ao mundo externo.


O Reflection permite a instanciação de novos objetos, a invocação de métodos e operações get / set em variáveis ​​de classe dinamicamente em tempo de execução, sem ter conhecimento prévio de sua implementação.

Class myObjectClass = MyObject.class;
Method[] method = myObjectClass.getMethods();

//Here the method takes a string parameter if there is no param, put null.
Method method = aClass.getMethod("method_name", String.class); 

Object returnValue = method.invoke(null, "parameter-value1");

No exemplo acima, o parâmetro nulo é o objeto no qual você deseja invocar o método. Se o método for estático, você fornecerá null. Se o método não for estático, durante a chamada, você precisará fornecer uma instância MyObject válida em vez de null.

O Reflection também permite que você acesse o membro privado / métodos de uma classe:

public class A{

  private String str= null;

  public A(String str) {
  this.str= str;
  }
}

.

A obj= new A("Some value");

Field privateStringField = A.class.getDeclaredField("privateString");

//Turn off access check for this field
privateStringField.setAccessible(true);

String fieldValue = (String) privateStringField.get(obj);
System.out.println("fieldValue = " + fieldValue);
  • Para inspeção de classes (também conhecida como introspecção) você não precisa importar o pacote de reflexão ( java.lang.reflect ). Metadados de classe podem ser acessados ​​através de java.lang.Class .

Reflection é uma API muito poderosa, mas pode retardar a aplicação se usada em excesso, pois resolve todos os tipos em tempo de execução.


Pelo meu entendimento:

Reflexão permite que o programador acesse entidades no programa dinamicamente. isto é, enquanto codifica uma aplicação se o programador não sabe sobre uma classe ou seus métodos, ele pode fazer uso de tal classe dinamicamente (em tempo de execução) usando reflexão.

É freqüentemente usado em cenários em que um nome de classe é alterado com frequência. Se tal situação ocorrer, será complicado para o programador reescrever o aplicativo e alterar o nome da classe repetidas vezes.

Em vez disso, usando a reflexão, é necessário se preocupar com um possível nome de classe em mudança.


Reflexão é um conjunto de funções que permite acessar as informações de tempo de execução do seu programa e modificá-lo (com algumas limitações).

É útil porque permite que você altere o tempo de execução dependendo da meta informação do seu programa, ou seja, você pode verificar o tipo de retorno de uma função e mudar a maneira de lidar com a situação.

Em C #, por exemplo, você pode carregar um assembly (um .dll) em tempo de execução e examiná-lo, navegando pelas classes e realizando ações de acordo com o que encontrou. Ele também permite criar uma instância de uma classe em tempo de execução, invocar seu método, etc.

Onde isso pode ser útil? Não é útil toda vez, mas para situações concretas. Por exemplo, você pode usá-lo para obter o nome da classe para fins de loggin, para criar dinamicamente manipuladores para eventos de acordo com o que está especificado em um arquivo de configuração e assim por diante ...


Um dos meus usos favoritos de reflexão é o método abaixo do Java dump. Ele usa qualquer objeto como parâmetro e usa a API de reflexão Java para imprimir cada nome e valor de campo.

import java.lang.reflect.Array;
import java.lang.reflect.Field;

public static String dump(Object o, int callCount) {
    callCount++;
    StringBuffer tabs = new StringBuffer();
    for (int k = 0; k < callCount; k++) {
        tabs.append("\t");
    }
    StringBuffer buffer = new StringBuffer();
    Class oClass = o.getClass();
    if (oClass.isArray()) {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("[");
        for (int i = 0; i < Array.getLength(o); i++) {
            if (i < 0)
                buffer.append(",");
            Object value = Array.get(o, i);
            if (value.getClass().isPrimitive() ||
                    value.getClass() == java.lang.Long.class ||
                    value.getClass() == java.lang.String.class ||
                    value.getClass() == java.lang.Integer.class ||
                    value.getClass() == java.lang.Boolean.class
                    ) {
                buffer.append(value);
            } else {
                buffer.append(dump(value, callCount));
            }
        }
        buffer.append(tabs.toString());
        buffer.append("]\n");
    } else {
        buffer.append("\n");
        buffer.append(tabs.toString());
        buffer.append("{\n");
        while (oClass != null) {
            Field[] fields = oClass.getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                buffer.append(tabs.toString());
                fields[i].setAccessible(true);
                buffer.append(fields[i].getName());
                buffer.append("=");
                try {
                    Object value = fields[i].get(o);
                    if (value != null) {
                        if (value.getClass().isPrimitive() ||
                                value.getClass() == java.lang.Long.class ||
                                value.getClass() == java.lang.String.class ||
                                value.getClass() == java.lang.Integer.class ||
                                value.getClass() == java.lang.Boolean.class
                                ) {
                            buffer.append(value);
                        } else {
                            buffer.append(dump(value, callCount));
                        }
                    }
                } catch (IllegalAccessException e) {
                    buffer.append(e.getMessage());
                }
                buffer.append("\n");
            }
            oClass = oClass.getSuperclass();
        }
        buffer.append(tabs.toString());
        buffer.append("}\n");
    }
    return buffer.toString();
}

exemplo simples de reflexão. Em um jogo de xadrez, você não sabe o que será movido pelo usuário em tempo de execução. reflexão pode ser usada para chamar métodos que já estão implementados em tempo de execução.

public class Test {

    public void firstMoveChoice(){
        System.out.println("First Move");
    } 
    public void secondMOveChoice(){
        System.out.println("Second Move");
    }
    public void thirdMoveChoice(){
        System.out.println("Third Move");
    }

    public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 
        Test test = new Test();
        Method[] method = test.getClass().getMethods();
        //firstMoveChoice
        method[0].invoke(test, null);
        //secondMoveChoice
        method[1].invoke(test, null);
        //thirdMoveChoice
        method[2].invoke(test, null);
    }

}

Reflexão é uma API que é usada para examinar ou modificar o comportamento de métodos, classes e interfaces em tempo de execução.

  1. As classes necessárias para reflexão são fornecidas no java.lang.reflect package .
  2. Reflexão nos dá informações sobre a classe à qual um objeto pertence e também os métodos dessa classe que podem ser executados usando o objeto.
  3. Através da reflexão, podemos invocar métodos em tempo de execução, independentemente do especificador de acesso usado com eles.

Os pacotes java.lang.reflect e java.lang.reflect fornecem classes para reflexão de java.

Reflexão pode ser usada para obter informações sobre -

  1. Classe O método getClass() é usado para obter o nome da classe à qual um objeto pertence.

  2. Construtores O método getConstructors() é usado para obter os construtores públicos da classe à qual um objeto pertence.

  3. Métodos O método getMethods() é usado para obter os métodos públicos da classe à qual um objeto pertence.

A API de reflexão é usada principalmente em:

IDE (Integrated Development Environment), por exemplo, Eclipse, MyEclipse, NetBeans etc.
Depurador e Ferramentas de Teste, etc.

Vantagens de usar a reflexão:

Recursos de extensibilidade: um aplicativo pode fazer uso de classes externas, definidas pelo usuário, criando instâncias de objetos de extensibilidade usando seus nomes totalmente qualificados.

Ferramentas de depuração e teste: os depuradores usam a propriedade de reflexão para examinar membros privados em classes.

Desvantagens:

Sobrecarga de desempenho: operações refletivas têm desempenho mais lento do que suas contrapartes não refletivas e devem ser evitadas em seções de código que são chamadas freqüentemente em aplicativos sensíveis ao desempenho.

Exposição de internos: O código reflexivo interrompe abstrações e, portanto, pode alterar o comportamento com atualizações da plataforma.

Ref: Reflexão Java javarevisited.blogspot.in


Usos da Reflexão

O Reflection é comumente usado por programas que exigem a capacidade de examinar ou modificar o comportamento em tempo de execução de aplicativos em execução na máquina virtual Java. Este é um recurso relativamente avançado e deve ser usado apenas por desenvolvedores que tenham uma forte compreensão dos fundamentos da linguagem. Com essa advertência em mente, a reflexão é uma técnica poderosa e pode permitir que os aplicativos executem operações que, de outra forma, seriam impossíveis.

Recursos de extensibilidade

Um aplicativo pode fazer uso de classes externas, definidas pelo usuário, criando instâncias de objetos de extensibilidade usando seus nomes totalmente qualificados. Navegadores de classe e ambientes de desenvolvimento visual Um navegador de classe precisa ser capaz de enumerar os membros das classes. Os ambientes de desenvolvimento visual podem se beneficiar do uso de informações de tipo disponíveis na reflexão para ajudar o desenvolvedor a escrever o código correto. Depuradores e Ferramentas de Teste Os depuradores precisam poder examinar membros privados em classes. Os chicotes de teste podem usar a reflexão para chamar sistematicamente APIs de conjunto detectáveis ​​definidas em uma classe, para garantir um alto nível de cobertura de código em um conjunto de testes.

Desvantagens da Reflexão

A reflexão é poderosa, mas não deve ser usada indiscriminadamente. Se for possível realizar uma operação sem usar reflexão, é preferível evitar usá-la. As seguintes preocupações devem ser lembradas ao acessar o código por meio de reflexão.

  • Sobrecarga de desempenho

Como a reflexão envolve tipos que são resolvidos dinamicamente, certas otimizações da máquina virtual Java não podem ser executadas. Consequentemente, as operações refletivas têm desempenho mais lento do que suas contrapartes não refletivas e devem ser evitadas em seções de código que são chamadas freqüentemente em aplicativos sensíveis ao desempenho.

  • Restrições de Segurança

O Reflection requer uma permissão de tempo de execução que pode não estar presente durante a execução sob um gerenciador de segurança. Esta é uma consideração importante para o código que deve ser executado em um contexto de segurança restrito, como em um Applet.

  • Exposição de Internals

Como a reflexão permite que o código execute operações que seriam ilegais em código não reflexivo, como acessar campos e métodos privados, o uso da reflexão pode resultar em efeitos colaterais inesperados, que podem tornar o código disfuncional e destruir a portabilidade. O código reflexivo interrompe abstrações e, portanto, pode alterar o comportamento com atualizações da plataforma.

fonte: A API de reflexão





terminology