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




10 Answers

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.

java reflection terminology

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.




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




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.




Exemplo:
Tomemos por exemplo um aplicativo remoto que dá ao seu aplicativo um objeto que você obtém usando seus métodos de API. Agora, com base no objeto, talvez seja necessário executar algum tipo de cálculo.
O provedor garante que o objeto pode ser de 3 tipos e precisamos realizar cálculos com base no tipo de objeto.
Portanto, podemos implementar em 3 classes, cada uma contendo uma lógica diferente. Obviamente, as informações sobre o objeto estão disponíveis em tempo de execução para que você não possa codificar estaticamente para executar computação, portanto, a reflexão é usada para instanciar o objeto da classe necessária para executar o cálculo objeto recebido do provedor.




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.




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);
    }

}



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;
   }    
}



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.




Reflection tem muitos usos . O que eu estou mais familiarizado, é ser capaz de criar código em tempo real.

IE: classes dinâmicas, funções, construtores - com base em qualquer dado (xml / array / sql results / hardcoded / etc ..)




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. Principalmente no nível da estrutura, os benefícios máximos da reflexão podem ser alcançados. O código de byte que é compilado se precisar de modificação extra em tempo de execução para exame, modificação, adição de mais código de byte em si mesmo ou outro programa ou outra estrutura no nível de método, nível de variável de instância, nível de construtor, reflexão de nível de anotação pode ser útil.

Suponha que você tenha um método add(Int a,int b) . O código de byte equivalente é suposto B1 . Se supor que você tenha 1000 métodos nomeados, add em seu sistema.Agora você quer verificar o valor do parâmetro ae bantes do método addser chamado. Assim, você pode colar seu código em outro programa ou estrutura que usa reflexão para examinar dinamicamente o valor do código de bytes usando Object.getClass.getMethod(). Existem várias classes para examinar. Pode adicionar mais operação antes do método addser chamado. Mas, o próprio programa ou outro programa ou estrutura não sabe sobre o objeto que tem um método chamado add. Principalmente na injeção de dependência, o uso de reflexão de programação orientada a aspectos é usado principalmente.




Related