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

2124

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.

Lehane
fonte
9
Para mim, é uma maneira de obter nomes de classes em tempo de execução e criar objetos dessa classe.
Nabin
65
porque essa é uma pergunta popular, eu gostaria de salientar que a reflexão (sem anotações) deve ser a última ferramenta para a solução de um problema. Eu o uso e adoro, mas cancela todas as vantagens da digitação estática do Java. Se você precisar, isole-o para a menor área possível (um método ou uma classe). É mais aceitável usá-lo em testes do que em código de produção. Nas anotações, tudo ficará bem - O ponto principal não é especificar os nomes de classe ou método como "Strings", se você puder evitá-lo.
Bill K
4
Além do comentário de @ BillK: A reflexão é muito poderosa, eu diria que é mágica. Com grandes poderes vem grandes responsabilidades. Use-o apenas se você souber o que está fazendo.
MC Emperor
Você pode evitar muitas das armadilhas envolvidas na reflexão usando o Manifold @Jailbreak. Ele fornece acesso direto, com segurança de tipo , a campos, métodos privados etc. Deixe o compilador Java verificar seu código com segurança e deixe o Manifold gerar o acesso de reflexão subjacente para você. Saiba mais: manifold.systems/docs.html#type-safe-reflection
Scott

Respostas:

1716

A reflexão do nome é usada para descrever o código que é capaz de inspecionar outro código no mesmo sistema (ou ele próprio).

Por exemplo, digamos que você tenha um objeto de tipo desconhecido em Java e gostaria de chamar um método 'doSomething', se houver algum. O sistema de digitação estática do Java não é realmente projetado para suportar isso, a menos que o objeto esteja em conformidade com uma interface conhecida, mas, usando reflexão, seu código pode olhar para o objeto e descobrir se ele possui um método chamado 'doSomething' e, em seguida, chamá-lo se você quer.

Portanto, para dar um exemplo de código disso em Java (imagine o objeto em questão):

Method method = foo.getClass().getMethod("doSomething", null);
method.invoke(foo, null);

Um caso de uso muito comum em Java é o uso com anotações. A JUnit 4, por exemplo, usará a reflexão para procurar nas suas classes os métodos marcados com a anotação @Test, e os chamará ao executar o teste de unidade.

Existem alguns bons exemplos de reflexão para você começar em http://docs.oracle.com/javase/tutorial/reflect/index.html

E, finalmente, sim, os conceitos são muito semelhantes em outras linguagens estaticamente tipadas que suportam reflexão (como C #). Em linguagens tipadas dinamicamente, o caso de uso descrito acima é menos necessário (já que o compilador permitirá que qualquer método seja chamado em qualquer objeto, falhando no tempo de execução se ele não existir), mas o segundo caso de procurar métodos marcados ou o trabalho de uma certa maneira ainda é comum.

Atualização de um comentário:

A capacidade de inspecionar o código no sistema e ver os tipos de objeto não é reflexão, mas sim Introspecção de tipo. Reflexão é então a capacidade de fazer modificações no tempo de execução usando a introspecção. A distinção é necessária aqui, pois alguns idiomas apóiam a introspecção, mas não apóiam a reflexão. Um exemplo é o C ++

Matt Sheppard
fonte
32
você pode explicar qual é o significado desse parâmetro nulo nesta linha Método method = foo.getClass (). getMethod ("doSomething", null);
Krsna Chaitanya
54
O nulo indica que não há parâmetros sendo passados ​​para o método foo. Consulte docs.oracle.com/javase/6/docs/api/java/lang/reflect/… , java.lang.Object ...) para obter detalhes.
Matt Sheppard
791
Só para esclarecer, pois isso tem muitos votos positivos. A capacidade de inspecionar o código no sistema e ver os tipos de objeto não é reflexão, mas sim Introspecção de tipo. Reflexão é então a capacidade de fazer modificações no tempo de execução usando a introspecção. A distinção é necessária aqui, pois alguns idiomas apóiam a introspecção, mas não apóiam a reflexão. Um exemplo é o C ++.
bigtunacan
39
Adoro a reflexão, mas se você tem controle sobre o código, o uso da reflexão, conforme especificado nesta resposta, é antinatural e, portanto, um abuso - você deve usar a Introspecção de Tipo (instanceof) e tipos fortes. Se existe alguma maneira além da reflexão de fazer algo, é assim que deve ser feito. A reflexão causa sérias dores de cabeça porque você perde todas as vantagens de usar uma linguagem de tipo estaticamente. Se você precisar, no entanto, mesmo assim, eu consideraria uma solução pré-empacotada como o Spring ou algo que encapsule completamente o reflexo necessário - IE: deixe que outra pessoa tenha dores de cabeça.
Bill K
6
@bigtunacan De onde você tirou essas informações? Vejo o termo "reflexão" usado na documentação oficial do Java da Oracle para descrever não apenas a capacidade de fazer alterações em tempo de execução, mas também a capacidade de ver o tipo de um objeto. Sem mencionar que a maioria das chamadas "tipo de introspecção" classes relacionadas (ex: Method, Constructor, Modifier, Field, Member, basicamente, aparentemente, todos, exceto Class) estão dentro do java.lang.*reflect*pacote. Talvez o conceito "reflexão" inclua abrangente "introspecção de tipo" e modificação em tempo de execução?
RestInPeace 29/04
246

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

Por exemplo, todos os objetos em Java possuem o método getClass(), que permite determinar a classe do objeto, mesmo que você não o conheça em tempo de compilação (por exemplo, se você o declarou como Object) - isso pode parecer trivial, mas essa 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, pois podem ser ligados em tempo de execução. O código pode ser gravado 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 extensivamente a reflexão por esse mesmo motivo. A maioria das outras linguagens modernas também usa a reflexão e, nas linguagens de script (como Python), elas são ainda mais integradas, pois parece mais natural no modelo de programação geral dessas linguagens.

Liedman
fonte
2
Portanto, em outras palavras, você pode criar uma instância com o nome qualificado e o compilador não irá reclamar disso (porque digamos que você use apenas uma String para o nome da classe). Em tempo de execução, se essa classe não estiver presente, você receberá uma exceção. Você meio que ignorou o compilador neste caso. Você poderia me dar um caso de uso específico para isso? Eu simplesmente não consigo imaginar quando eu escolheria.
Fernando Gabrieli
3
@FernandoGabrieli Embora seja verdade que é fácil criar erros de tempo de execução com reflexão, também é perfeitamente possível usar a reflexão sem arriscar exceções de tempo de execução. Como sugerido na minha resposta, um uso comum de reflexão é para bibliotecas ou estruturas, que explicitamente não podem conhecer a estrutura do aplicativo em tempo de compilação, pois eles são compilados separadamente do aplicativo. Qualquer biblioteca que use "código por convenção" provavelmente usará reflexão, mas não necessariamente usando seqüências de caracteres mágicas.
Liedman
1
C++possui informações do tipo em tempo de execução. RTTI
Ayxan
114

Um dos meus usos favoritos da reflexão é o método Java dump abaixo. Ele pega qualquer objeto como parâmetro e usa a API de reflexão Java para imprimir todos os nomes e valores de campos.

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();
}
Ben Williams
fonte
8
Como o Callcount deve ser definido?
Tom
8
Eu recebi uma exceção no segmento "AWT-EventQueue-0" java.lang.StackOverflowError quando executei isso.
Tom
3
@ Tom callCountdeve estar definido como zero. Seu valor é usado para determinar quantas guias devem preceder cada linha de saída: cada vez que o dump precisar despejar um "subobjeto", a saída será impressa como aninhada no pai. Esse método se mostra útil quando envolvido em outro. Considere printDump(Object obj){ System.out.println(dump(obj, 0)); }.
FNY
1
O java.lang.StackOverflowError pode ser criado em caso de referências circulares, por causa do recursão verificado: buffer.append (despejo (valor, CallCount))
Arnaud P
4
Você pode liberar seu código especificamente para o domínio público, por favor?
stolsvik
84

Usos da Reflexão

O Reflection é comumente usado por programas que requerem 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 ressalva, a reflexão é uma técnica poderosa e pode permitir que os aplicativos realizem 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 particulares nas classes. Os chicotes de teste podem fazer uso da reflexão para chamar sistematicamente APIs de um conjunto detectável definido 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 executar uma operação sem usar reflexão, é preferível evitar usá-la. As seguintes preocupações devem ser lembradas ao acessar o código via reflexão.

  • Sobrecarga de desempenho

Como a reflexão envolve tipos resolvidos dinamicamente, determinadas otimizações da máquina virtual Java não podem ser executadas. Conseqüentemente, as operações reflexivas têm desempenho mais lento do que suas contrapartes não refletivas e devem ser evitadas nas seções de código que são chamadas frequentemente 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 quando executado em um gerenciador de segurança. Isso é importante para o código que precisa ser executado em um contexto de segurança restrito, como em um Applet.

  • Exposição de Internos

Como a reflexão permite que o código execute operações que seriam ilegais no 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 quebra as abstrações e, portanto, pode alterar o comportamento com as atualizações da plataforma.

fonte: a API de reflexão

Desmond Smith
fonte
44

A reflexão é um mecanismo essencial para permitir que um aplicativo ou estrutura funcione com código que talvez ainda não tenha sido gravado!

Tomemos, por exemplo, seu arquivo web.xml típico. Isso conterá uma lista de elementos de servlet, que contêm elementos de classe de servlet aninhados. O contêiner de servlet processará o arquivo web.xml e criará uma nova instância nova de cada classe de servlet por meio de reflexão.

Outro exemplo seria a API Java para análise XML (JAXP) . Onde um provedor de analisador XML é 'conectado' por meio de propriedades conhecidas do sistema, que são usadas para construir novas instâncias por meio de reflexão.

E, finalmente, o exemplo mais abrangente é o Spring, que usa reflexão para criar seus beans e pelo uso pesado de proxies

conjunto de ferramentas
fonte
36

Nem todas as línguas apóiam a reflexão, mas os princípios geralmente são os mesmos nas línguas que a apóiam.

Reflexão é a capacidade de "refletir" na estrutura do seu programa. Ou mais concreto. Para examinar os objetos e as classes que você possui e recuperar 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 todos os lugares que você deseja poder conectar dinamicamente classes ao seu código. Muitos mapeadores relacionais de objetos usam reflexão para poder instanciar objetos de bancos de dados sem saber antecipadamente quais objetos eles usarão. As arquiteturas de plug-in são outro lugar em que a reflexão é útil. Ser capaz de carregar código dinamicamente e determinar se existem tipos que implementam a interface correta para uso como plug-in é importante nessas situações.

Mendelt
fonte
Eu preciso instanciar objetos com base nos dados presentes no DB. Eu acredito que é disso que você está falando. Código de exemplo me ajudaria muito. Desde já, obrigado.
Atom
34

O Reflection permite instanciação de novos objetos, invocação de métodos e operações de obtenção / configuração de 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 chamar o método. Se o método for estático, você fornecerá nulo. Se o método não for estático, ao invocar, você precisará fornecer uma instância MyObject válida em vez de nula.

O Reflection também permite acessar membros / métodos privados 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). Os metadados da classe podem ser acessados ​​através java.lang.Class.

O Reflection é uma API muito poderosa, mas pode desacelerar o aplicativo se usado em excesso, pois resolve todos os tipos em tempo de execução.

Nikhil Shekhar
fonte
21

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 saber os nomes das classes, métodos etc. em tempo de compilação. Também é possível instanciar novos objetos, chamar métodos e obter / definir valores de campo usando reflexão.

Um exemplo rápido do Java Reflection para mostrar como é o uso do 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 nessa classe, itera os métodos e imprime seus nomes.

Exatamente como tudo isso funciona é explicado aqui

Edit : Depois de quase 1 ano, estou editando esta resposta, enquanto lia sobre reflexão, recebi mais alguns usos do Reflection.

  • O Spring usa a configuração de bean, como:


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

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

Ele usará novamente a reflexão para obter o configurador apropriado para o elemento <property> e definir seu valor para o valor especificado.

  • O Junit usa o Reflection especialmente para testar métodos Privado / Protegido.

Para métodos particulares,

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

Para campos particulares,

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

Exemplo:

Tomemos, por exemplo, um aplicativo remoto que fornece ao aplicativo um objeto que você obtém usando os Métodos da API. Agora, com base no objeto, você pode precisar executar algum tipo de cálculo.

O provedor garante que o objeto pode ser de três tipos e precisamos executar o cálculo com base em que tipo de objeto.

Portanto, podemos implementar em 3 classes, cada uma contendo uma lógica diferente. Obviamente, as informações do objeto estão disponíveis em tempo de execução; portanto, você não pode codificar estaticamente para executar a computação, portanto, a reflexão é usada para instanciar o objeto da classe que você precisa para executar a computação com base no objeto recebido do provedor.

human.js
fonte
Eu preciso de algo semelhante .. Um exemplo seria me ajudar muito como eu sou novo para conceitos reflexão ..
Atom
2
Estou confuso: você não pode usar instanceofpara determinar o tipo de objeto em tempo de execução?
Ndm13 11/0118
19

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

}
Isuru Jayakantha
fonte
18

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

  1. As classes necessárias para reflexão são fornecidas em java.lang.reflect package.
  2. A reflexão nos fornece 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.lange java.lang.reflectfornecem classes para reflexão de java.

O Reflection pode ser usado para obter informações sobre -

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

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

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

A API de reflexão é usada principalmente em:

IDE (ambiente de desenvolvimento integrado), 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: as operações reflexivas têm desempenho mais lento do que suas contrapartes não refletivas e devem ser evitadas nas seções de código que são chamadas com freqüência em aplicativos sensíveis ao desempenho.

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

Ref: Reflexão Java javarevisited.blogspot.in

roottraveller
fonte
4
Eu acrescentaria às desvantagens " quebra a refatoração ". Para mim, esse é o principal motivo para evitar a reflexão o máximo possível.
SantiBailors
Portanto, permite-nos (por exemplo), inspecionar as classes que temos (se temos instâncias delas ou não), correto? Com isso, quero dizer, obtenha seus métodos ou construtores e use-os para criar novas instâncias / invocá-los. Por que dizemos "alterando o comportamento do programa" se o comportamento já existe, mas com código diferente? Por que isso é chamado de "reflexão"? Obrigado
Fernando Gabrieli
15

Conforme meu entendimento:

O Reflection permite que o programador acesse entidades no programa dinamicamente. ou seja, ao codificar um aplicativo se o programador não souber sobre uma classe ou seus métodos, ele pode fazer uso dessa classe dinamicamente (em tempo de execução) usando reflexão.

É freqüentemente usado em cenários em que o nome de uma classe muda frequentemente. Se essa situação surgir, é complicado para o programador reescrever o aplicativo e alterar o nome da classe repetidamente.

Em vez disso, usando a reflexão, é necessário se preocupar com a possibilidade de alterar o nome da classe.

Pramod
fonte
15

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 alterar o comportamento do tempo de execução, dependendo das meta informações do seu programa, ou seja, você pode verificar o tipo de retorno de uma função e alterar a maneira como lida com a situação.

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

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

Jorge Córdoba
fonte
11

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

Com o Reflection API, você pode escrever um toString()método 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;
   }    
}
nazar_art
fonte
11

Reflexão é deixar o objeto ver sua aparência. Este argumento não parece ter nada a ver com reflexão. De fato, essa é a capacidade de "auto-identificação".

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

Marcus Thornton
fonte
type (), isinstance (), callable (), dir () e getattr (). .... estas são chamadas de reflexão Pythonic
AnthonyJClink
9

Na página de documentação do java

java.lang.reflectO pacote 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 das restrições de segurança.

AccessibleObjectpermite a supressão das verificações de acesso, se necessário ReflectPermission.

As classes neste pacote, além de java.lang.Classacomodar aplicativos como depuradores, intérpretes, inspetores de objetos, navegadores de classe e serviços como Object Serializatione JavaBeansque precisam acessar os membros públicos de um objeto de destino (com base em sua classe de tempo de execução) ou os membros declarados por uma dada classe

Inclui a seguinte funcionalidade.

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

Dê uma olhada neste link de documentação para os métodos expostos por Classclasse.

Deste artigo (de Dennis Sosnoski, Presidente da Sosnoski Software Solutions, Inc) e deste artigo (pdf de explorações de segurança):

Eu posso ver desvantagens consideráveis ​​do que o uso do 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 maneiras 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. 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 violar as principais restrições de segurança Java, como proteção de acesso a dados e segurança de tipo

Abusos gerais:

  1. Carregamento de classes restritas,
  2. Obtenção de 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 pergunta 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 de dentro de um código do sistema também pode facilmente levar ao comprometimento de um modo de segurança Java l. Portanto, use esse recurso com moderação

Ravindra babu
fonte
Uma maneira de evitar os problemas de desempenho do Reflection em alguns casos é fazer com que uma classe Woozleexamine outras classes na inicialização para ver quais possuem um RegisterAsWoozleHelper()método estático e invoque todos os métodos encontrados com um retorno de chamada que eles podem usar para falar Woozlesobre si mesmos, evitando precisa usar o Reflection enquanto, por exemplo, desserializa dados.
supercat 01/02
9

Como o próprio nome sugere, ele reflete o que contém, por exemplo, método de classe, etc, além de fornecer recurso para chamar a criação de método dinamicamente em tempo de execução.

É usado por muitas estruturas e aplicativos sob a madeira para chamar serviços sem realmente conhecer o código.

Mohammed Sarfaraz
fonte
7

O Reflection permite escrever códigos mais genéricos. Ele permite que você crie um objeto no tempo de execução e chame seu método no tempo de execução. Portanto, o programa pode ser feito altamente parametrizado. Também permite a introspecção do objeto e da classe para detectar suas variáveis ​​e métodos expostos ao mundo exterior.

saumik gupta
fonte
6

Reflectiontem muitos usos . O que eu estou mais familiarizado é ser capaz de criar código rapidamente.

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

Ess Kay
fonte
1
Esta resposta seria muito melhor se você desse apenas um exemplo incomum de código gerado a partir de um resultado SQL ou arquivo XML etc.
ThisClark
Sem problemas. Usei a reflexão em um aplicativo do Windows que gera dinamicamente a interface com base no XML retirado de um banco de dados.
Ess Kay
Então, basicamente, há uma classe que criei que mostra ao usuário um relatório. Este relatório possui parâmetros como Data (de a) id ou qualquer outra coisa. Esta informação é armazenada em xml. Então, primeiro temos uma seleção de relatório. Com base no relatório selecionado, o formulário obtém o xml. Depois que o xml é recuperado, ele usa a reflexão para criar uma classe com campos baseados nos tipos refletidos. Depois de mudar para um relatório diferente, a barra é limpa e novos campos são gerados com base no xml. Portanto, é essencialmente uma forma dinâmica baseada na reflexão. Eu também usado em outras maneiras, mas esta deve ser a esperança suffecient que ajuda
Ess Kay
3

Eu quero responder a esta pergunta pelo exemplo. Antes de tudo, o Hibernateprojeto usa Reflection APIpara gerar CRUDinstruções para reduzir o abismo entre o aplicativo em execução e o armazenamento de persistência. Quando as coisas mudam no domínio, Hibernateé preciso saber sobre elas para persistir no armazenamento de dados e vice-versa.

Alternativamente funciona Lombok Project. Apenas injeta código no momento da compilação, resultando na inserção de código nas classes de domínio. (Eu acho que é bom para getters e setters)

Hibernateescolhido reflectionporque tem um impacto mínimo no processo de criação de um aplicativo.

E do Java 7 temos MethodHandles, que funciona como Reflection API. Nos projetos, para trabalhar com loggers, basta copiar e colar o próximo código:

Logger LOGGER = Logger.getLogger(MethodHandles.lookup().lookupClass().getName());

Porque é difícil cometer erros de digitação neste caso.

BSeitkazin
fonte
3

Como eu acho melhor explicar pelo exemplo e nenhuma das respostas parece fazer isso ...

Um exemplo prático do uso de reflexões seria um servidor de linguagem Java escrito em Java ou um servidor de linguagem PHP escrito em PHP, etc. O servidor de linguagem fornece suas habilidades de IDE como preenchimento automático, pular para definição, ajuda de contexto, tipos de dicas e muito mais. Para que todos os nomes de tags (palavras que podem ser preenchidas automaticamente) mostrem todas as correspondências possíveis à medida que você digita, o Servidor de Idiomas precisa inspecionar tudo sobre a classe, incluindo blocos de documentos e membros privados. Para isso, é necessário refletir a referida classe.

Um exemplo diferente seria um teste de unidade de um método privado. Uma maneira de fazer isso é criar uma reflexão e alterar o escopo do método para público na fase de configuração do teste. É claro que se pode argumentar que métodos privados não devem ser testados diretamente, mas esse não é o ponto.

cprn
fonte