reflexivité - retourner un objet java




Qu'est-ce que la réflexion et pourquoi est-ce utile? (14)

La réflexion est la capacité d'un langage à inspecter et à appeler dynamiquement des classes, des méthodes, des attributs, etc. à l'exécution.

Par exemple, tous les objets en Java ont la méthode getClass() , qui vous permet de déterminer la classe de l'objet même si vous ne le connaissez pas au moment de la compilation (par exemple si vous l'avez déclaré en tant Object ). la réflexion n'est pas possible dans les langages moins dynamiques tels que C++ . Des utilisations plus avancées vous permettent de lister et d'appeler des méthodes, des constructeurs, etc.

La réflexion est importante car elle vous permet d'écrire des programmes qui ne doivent pas "tout" savoir à la compilation, ce qui les rend plus dynamiques, puisqu'ils peuvent être liés à l'exécution. Le code peut être écrit contre des interfaces connues, mais les classes réelles à utiliser peuvent être instanciées en utilisant la réflexion à partir des fichiers de configuration.

Beaucoup de cadres modernes utilisent largement la réflexion pour cette raison. La plupart des autres langages modernes utilisent également la réflexion, et dans les langages de script (tels que Python), ils sont encore plus étroitement intégrés, car ils se sentent plus naturels dans le modèle de programmation générale de ces langages.

Qu'est-ce que la réflexion, et pourquoi est-ce utile?

Je suis particulièrement intéressé par Java, mais je suppose que les principes sont les mêmes dans toutes les langues.


Comme le nom lui-même suggère qu'il reflète ce qu'il contient par exemple la méthode de classe, etc en dehors de fournir une fonctionnalité pour invoquer la méthode de création d'instance dynamiquement au moment de l'exécution.

Il est utilisé par de nombreux frameworks et applications sous le bois pour invoquer des services sans réellement connaître le code.


Exemple :
Prenons par exemple une application distante qui donne à votre application un objet que vous obtenez en utilisant ses méthodes API. Maintenant, basé sur l'objet, vous devrez peut-être effectuer une sorte de calcul.
Le fournisseur garantit que l'objet peut être de 3 types et nous devons effectuer un calcul basé sur quel type d'objet.
Nous pouvons donc implémenter en 3 classes contenant chacune une logique différente. Évidemment, l'information d'objet est disponible en runtime donc vous ne pouvez pas coder statiquement pour effectuer le calcul donc la réflexion est utilisée pour instancier l'objet de la classe dont vous avez besoin pour effectuer le calcul. objet reçu du fournisseur.


Java Reflection est assez puissant et peut être très utile. Java Reflection permet d'inspecter des classes, des interfaces, des champs et des méthodes lors de l'exécution, sans connaître les noms des classes, des méthodes, etc. lors de la compilation. Il est également possible d' instancier de nouveaux objets, d'appeler des méthodes et d'obtenir / définir des valeurs de champs en utilisant la réflexion.

Un exemple rapide de réflexion Java pour vous montrer à quoi ressemble la réflexion:

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

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

Cet exemple obtient l'objet Class de la classe appelée MyObject. À l'aide de l'objet de classe, l'exemple obtient une liste des méthodes de cette classe, itère les méthodes et imprime leurs noms.

Exactement comment tout cela fonctionne est expliqué ici

Edit : Après presque 1 an je suis en train d'éditer cette réponse car en lisant sur la réflexion j'ai eu peu d'autres utilisations de Reflection.

  • Spring utilise une configuration de bean telle que:


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

Lorsque le contexte Spring traite cet élément <bean>, il utilise Class.forName (String) avec l'argument "com.example.Foo" pour instancier cette classe.

Il utilisera à nouveau la réflexion pour obtenir le setter approprié pour l'élément <property> et définir sa valeur sur la valeur spécifiée.

  • Junit utilise Reflection spécialement pour tester les méthodes Private / Protected.

Pour les méthodes privées,

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

Pour les champs privés,

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

Je veux juste ajouter quelque chose à tout ce qui était listé.

Avec l' API Reflection, vous pouvez écrire une toString() universelle pour n'importe quel objet.

C'est utile lors du débogage.

Voici un exemple:

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

L'une de mes utilisations préférées de la réflexion est la méthode de vidage Java ci-dessous. Il prend n'importe quel objet en paramètre et utilise l'API de réflexion Java pour imprimer chaque nom et valeur de champ.

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

La réflexion est de laisser l'objet voir leur apparence. Cet argument n'a rien à voir avec la réflexion. En fait, c'est la capacité de «s'auto-identifier».

La réflexion elle-même est un mot pour de tels langages qui manquent de capacité de connaissance de soi et d'auto-détection comme Java et C #. Parce qu'ils n'ont pas la capacité de connaissance de soi, quand nous voulons observer à quoi cela ressemble, nous devons avoir une autre chose pour refléter à quoi cela ressemble. D'excellents langages dynamiques tels que Ruby et Python peuvent percevoir la réflexion de leurs propres sans l'aide d'autres individus. Nous pouvons dire que l'objet de Java ne peut pas percevoir à quoi il ressemble sans un miroir, qui est un objet de la classe de réflexion, mais un objet en Python peut le percevoir sans miroir. C'est pourquoi nous avons besoin de réflexion en Java.


La réflexion est un ensemble de fonctions qui vous permet d'accéder aux informations d'exécution de votre programme et de le modifier (avec certaines limitations).

C'est utile car cela vous permet de changer le comportement d'exécution en fonction des méta-informations de votre programme, c'est-à-dire que vous pouvez vérifier le type de retour d'une fonction et changer la façon dont vous gérez la situation.

En C # par exemple, vous pouvez charger un assembly (.dll) en runtime et l'examiner, naviguer dans les classes et effectuer des actions en fonction de ce que vous avez trouvé. Il vous permet également de créer une instance d'une classe à l'exécution, d'appeler sa méthode, etc.

Où peut-il être utile? N'est pas utile à chaque fois sauf pour des situations concrètes. Par exemple, vous pouvez l'utiliser pour obtenir le nom de la classe à des fins de connexion, pour créer des gestionnaires de manière dinamique pour les événements en fonction de ce qui est spécifié sur un fichier de configuration et ainsi de suite ...


La réflexion permet l'instanciation de nouveaux objets, l'invocation de méthodes et l'obtention / la définition dynamique d'opérations sur des variables de classe au moment de l'exécution, sans avoir préalablement connaissance de son implémentation.

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

Dans l'exemple ci-dessus, le paramètre null est l'objet sur lequel vous voulez appeler la méthode. Si la méthode est statique, vous indiquez null. Si la méthode n'est pas statique, vous devez fournir une instance MyObject valide au lieu de null lors de l'appel.

La réflexion vous permet également d'accéder aux membres privés / méthodes d'une 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);
  • Pour l'inspection des classes (également appelée introspection), vous n'avez pas besoin d'importer le paquet de réflexion ( java.lang.reflect ). Les métadonnées de classe sont accessibles via java.lang.Class .

Reflection est une API très puissante mais elle peut ralentir l'application si elle est utilisée en excès, car elle résout tous les types lors de l'exécution.


La réflexion vous donne la possibilité d'écrire du code plus générique. Il vous permet de créer un objet lors de l'exécution et d'appeler sa méthode lors de l'exécution. Par conséquent, le programme peut être paramétré en profondeur. Il permet également d'introspecter l'objet et la classe pour détecter ses variables et la méthode exposée au monde extérieur.


Toutes les langues ne supportent pas la réflexion, mais les principes sont généralement les mêmes dans les langues qui la supportent.

La réflexion est la capacité de «réfléchir» sur la structure de votre programme. Ou plus concret. Pour regarder les objets et les classes que vous avez et récupérer par programme des informations sur les méthodes, les champs et les interfaces qu'ils implémentent. Vous pouvez également regarder des choses comme des annotations.

C'est utile dans beaucoup de situations. Partout où vous voulez être en mesure de brancher dynamiquement des classes dans votre code. Beaucoup de mappeurs relationnels d'objets utilisent la réflexion pour être capables d'instancier des objets à partir de bases de données sans savoir à l'avance quels objets ils vont utiliser. Les architectures plug-in sont un autre endroit où la réflexion est utile. Pouvoir charger dynamiquement du code et déterminer s'il existe des types implémentant la bonne interface à utiliser en tant que plugin est important dans ces situations.


exemple simple pour la réflexion. Dans un jeu d'échecs, vous ne savez pas ce qui sera déplacé par l'utilisateur au moment de l'exécution. La réflexion peut être utilisée pour appeler des méthodes qui sont déjà implémentées lors de l'exécution.

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

}

Reflection est une API utilisée pour examiner ou modifier le comportement des méthodes, des classes et des interfaces lors de l'exécution.

  1. Les classes requises pour la réflexion sont fournies dans le java.lang.reflect package .
  2. La réflexion nous donne des informations sur la classe à laquelle un objet appartient et également les méthodes de cette classe qui peuvent être exécutées en utilisant l'objet.
  3. Grâce à la réflexion, nous pouvons invoquer des méthodes à l'exécution, quel que soit le spécificateur d'accès utilisé avec eux.

Les paquets java.lang et java.lang.reflect fournissent des classes pour la réflexion java.

La réflexion peut être utilisée pour obtenir des informations sur -

  1. Classe La méthode getClass() est utilisée pour obtenir le nom de la classe à laquelle un objet appartient.

  2. Constructeurs La méthode getConstructors() est utilisée pour obtenir les constructeurs publics de la classe à laquelle appartient un objet.

  3. Méthodes La méthode getMethods() est utilisée pour obtenir les méthodes publiques de la classe à laquelle appartient un objet.

L' API Reflection est principalement utilisée dans:

IDE (environnement de développement intégré), par exemple Eclipse, MyEclipse, NetBeans, etc.
Débogueur et outils de test, etc.

Avantages de l'utilisation de la réflexion:

Fonctions d'extensibilité: Une application peut utiliser des classes externes définies par l'utilisateur en créant des instances d'objets d'extensibilité en utilisant leurs noms complets.

Outils de débogage et de test: les débogueurs utilisent la propriété de réflexion pour examiner les membres privés sur les classes.

Désavantages:

Surcoût lié aux performances: les opérations Reflective ont des performances plus lentes que leurs homologues non-réfléchissantes et doivent être évitées dans les sections de code fréquemment appelées applications sensibles aux performances.

Exposition des Internes: Le code réfléchissant brise les abstractions et peut donc changer le comportement avec les mises à jour de la plateforme.

Réf: Java Reflection javarevisited.blogspot.in


Utilisations de la réflexion

La réflexion est couramment utilisée par les programmes qui requièrent la possibilité d'examiner ou de modifier le comportement d'exécution des applications s'exécutant dans la machine virtuelle Java. C'est une fonctionnalité relativement avancée et ne devrait être utilisée que par des développeurs qui maîtrisent les bases de la langue. Avec cette réserve à l'esprit, la réflexion est une technique puissante et peut permettre aux applications d'effectuer des opérations qui seraient autrement impossibles.

Fonctions d'extensibilité

Une application peut utiliser des classes externes définies par l'utilisateur en créant des instances d'objets d'extensibilité en utilisant leurs noms pleinement qualifiés. Navigateurs de classes et environnements de développement visuel Un navigateur de classes doit pouvoir énumérer les membres des classes. Les environnements de développement visuel peuvent bénéficier de l'utilisation d'informations de type disponibles en réflexion pour aider le développeur à écrire du code correct. Débogueurs et outils de test Les débogueurs doivent pouvoir examiner les membres privés dans les classes. Les faisceaux de tests peuvent utiliser la réflexion pour appeler systématiquement une API de jeu détectable définie sur une classe, afin d'assurer un niveau élevé de couverture de code dans une suite de tests.

Inconvénients de la réflexion

La réflexion est puissante, mais ne doit pas être utilisée sans discernement. S'il est possible d'effectuer une opération sans utiliser de réflexion, il est préférable d'éviter de l'utiliser. Les préoccupations suivantes doivent être gardées à l'esprit lors de l'accès au code par réflexion.

  • Frais généraux de performance

Parce que la réflexion implique des types qui sont résolus dynamiquement, certaines optimisations de machines virtuelles Java ne peuvent pas être effectuées. Par conséquent, les opérations réfléchissantes ont des performances plus lentes que leurs homologues non réfléchissantes et doivent être évitées dans les sections de code fréquemment appelées applications sensibles aux performances.

  • Restrictions de sécurité

La réflexion nécessite une autorisation d'exécution qui peut ne pas être présente lors de l'exécution sous un gestionnaire de sécurité. C'est une considération importante pour le code qui doit s'exécuter dans un contexte de sécurité restreint, comme dans une applet.

  • Exposition des Internes

Puisque la réflexion permet au code d'effectuer des opérations qui seraient illégales dans un code non-réfléchissant, comme l'accès à des champs et méthodes privés, l'utilisation de la réflexion peut entraîner des effets secondaires inattendus qui peuvent rendre le code dysfonctionnel et détruire la portabilité. Le code réfléchi brise les abstractions et peut donc changer le comportement avec les mises à niveau de la plate-forme.

source: l' API Reflection





terminology