Java: Quels scénarios appellent l'utilisation de la réflexion?


Donc, en lisant certains articles, le message que j'en ai sorti était de pouvoir modifier des champs et définir des valeurs sur des classes en temps réel sans recompiler.

Est-il donc possible de le faire à des classes créées par une bibliothèque java tierce dont aucun code source n'est disponible / est-il possible d'utiliser la réflexion pour modifier les instances de classe au moment de l'exécution?

Dans quels autres scénarios la réflexion est-elle couramment utilisée?

J'essaie de comprendre comment la réflexion peut être applicable.

Author: Yu Zhang, 2012-02-10

7 answers

Chaque fois que vous avez affaire à une chaîne lors de l'exécution et que vous souhaitez traiter une partie de cette chaîne comme un identifiant dans la langue.

  1. Appel de procédure distante treat traiter une partie d'un message reçu sur le réseau comme un nom de méthode.
  2. Sérialisation et désérialisation convert convertissez les noms de champs en chaîne afin que vous puissiez écrire les champs de l'objet dans un flux et les convertir ultérieurement en objet.
  3. Mappages objet-relationnels maintain maintenir une relation entre les champs objet et colonnes dans une base de données.
  4. Interfaces avec des langages de script typés dynamiquement turn transformez une valeur de chaîne produite par un langage de script en référence à un champ ou une méthode sur un objet.

Il peut également être utilisé pour permettre l'émulation de fonctionnalités linguistiques dans la langue. Considérons la ligne de commande java com.example.MyClass qui transforme une chaîne en nom de classe. Cela ne nécessite pas de réflexion, car l'exécutable java peut transformer un fichier .class en code, mais sans réflexion ne serait pas en mesure d'écrire java com.example.Wrapper com.example.MyClassWrapper délègue à son argument comme dans:

class Wrapper {
  public static void main(String... argv) throws Exception {
    // Do some initialization or other work.
    Class<?> delegate = Class.forName(argv[0]);
    Method main = delegate.getMethod("main", String[].class);
    main.apply(null, Arrays.asList(argv).subList(1, argv.length).toArray(argv));
  }
}
 11
Author: Mike Samuel, 2015-01-20 13:55:46

Un autre cas développant desEs comme eclipse / netbeans etc., pour déterminer quelles méthodes dans une classe abstraite doivent être implémentées par une classe enfant, et écrire automatiquement les appels de méthode manquants pour vous (un exemple).

 3
Author: kosa, 2012-02-10 04:20:42

La Réflexion est utilisé lorsqu'il est nécessaire d'aller dans l'autre classes in deeper level. Ainsi, dans la plupart des cas, ces implémenteurs ont le comportement conteneur. Par exemple, l'injection de dépendance se fait principalement avec l'utilisation de la réflexion. Si vous avez besoin d'un framework comme exemple pour cela, Spring effectue ses travaux d'injection de dépendance à l'aide de reflection API.

Vous trouverez également des réflexions utilisées dans les coulisses dans un grand nombre de domaines. Par exemple, si vous avez utilisé JAXB, alors beaucoup de le marshalling / unmarshalling de le XML sera fait en utilisant des réflexions. L'utilisation d'annotations dans votre code entraîne souvent dans les réflexions utilisées dans les coulisses. Lors de l'exécution de tests unitaires, en particulier lorsque se moquant des classes et / ou des méthodes, a souvent beaucoup de réflexions le code utilisé.

 2
Author: Sumit Singh, 2012-02-10 05:18:15

Les frameworks d'injection commeGuice ou Spring utilisent la réflexion pour vous aider à créer des instances d'objets lors de l'exécution.

 1
Author: Louis Wasserman, 2012-02-10 04:24:49

La réflexion est également utile dans les cas où une configuration est requise pour enchaîner les choses. Par exemple, dans une application que j'ai écrite, j'ai une annotation @Report("débits") qui est simplement ajoutée aux méthodes qui génèrent des rapports. Ensuite, dans la configuration XML, un utilisateur peut simplement ajouter:

<requiredReports="debits,blah,another"/>

Cela réduit au minimum le code de la plaque de chaudière du mappage du code XML à la méthode réelle, car reflection peut découvrir les méthodes de rapport et les rendre disponibles directement.

 0
Author: Jaco Van Niekerk, 2016-12-30 09:03:49

On m'a demandé de créer une solution pour l'instruction ci-dessous.

"1) Un service diff qui: * peut calculer les différences entre deux objets et renvoyer le résultat "diff" * peut appliquer un "diff" créé précédemment à un objet original, de sorte que l'objet renvoyé correspond à l'objet modifié qui a été utilisé pour calculer le diff. "

Cela aurait été très difficile sans utiliser la réflexion. En utilisant la réflexion je pourrais énumérer tous les inconnus éléments, propriétés et méthodes de classe de l'objet. Je pourrais les utiliser pour obtenir les valeurs contenues dans l'objet. Je pourrais comparer les valeurs d'objets d'origine et modifiées, créer un objet "diff" reflétant les changements entre les deux objets.

En utilisant la réflexion Java, je pourrais alors lire les instructions dans l'objet "diff" et les appliquer à l'objet d'origine. Java reflection m'a donné les outils nécessaires pour changer les valeurs sur les propriétés inconnues de l'objet d'origine. Je pourrais invoquer setter méthodes et types d'instanciation si nécessaire si la propriété d'origine était null pour définir la valeur modifiée sur l'objet d'origine.

L'application "diff" fonctionne sur deux objets du même type, mais ils peuvent être de n'importe quel type, les deux objets doivent simplement être du même type.

La réflexion est très puissante et nous permet de créer de véritables méthodes, fonctions, bibliothèques et systèmes polymorphes génériques, où le type d'objet passé n'a pas besoin d'être connu au moment de la compilation. Cela s'applique lors de l'utilisation de Réflexion Java et génériques ensemble, une combinaison très puissante.

À la fin de, j'ai également utilisé Java Reflection pour créer une fonction de tri générique, qui pourrait trier n'importe quelle liste de n'importe quel type de classe, en utilisant n'importe quelle propriété de la classe comme tri key.As tant que la méthode appelante transmet la liste et le nom de la propriété à utiliser, la méthode renvoie une liste triée.

 0
Author: Groenlantern, 2017-04-11 08:23:52

Voici quelques cas pour utiliser la réflexion dans

public class Main {

    public static void main(String[] args) {

        displayProperties(Stage.class);
    }

    public static void displayProperties(Class class) {
        boolean hasParam = false;
        boolean hasReturn = false;
        ArrayList<Method> propMethods = new ArrayList<>();
        Method[] methods = clazz.getMethods();
        for (Method m: methods) {

            Parameter[] paraType = m.getParameters();
            if(m.getParameterCount()<2) {
                if ((m.getReturnType() == void.class && paraType.length == 1) || (m.getReturnType() != void.class && paraType.length == 0)) {
                    //Get the properties alone
                    propMethods.add(m);
                }
            }

        }
        for (int i = 0; i < propMethods.size(); i++) {

            if (propMethods.get(i).getName().startsWith("get") || propMethods.get(i).getName().startsWith("set")) {

                System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName().substring(3)+"( "+propMethods.get(i).getReturnType().getTypeName()+" )");
            } else
                System.out.println(readWrite(propMethods.get(i), propMethods) + " " + propMethods.get(i).getName() + "( "+propMethods.get(i).getReturnType().getTypeName()+" )");
        }

    }

    public static String readWrite(Method method, ArrayList<Method> propMeths) {

        ArrayList<Method> temp;
        temp = propMeths;

        boolean readIn = false;
        boolean writeIn = false;
        String onlyName = method.getName().substring(3);

        for (int i = 0; i < temp.size(); i++) {
            //use the substring--

            if (temp.get(i).getName().startsWith("get") && temp.get(i).getName().endsWith(onlyName)) {
                readIn = true;
            }
            if (temp.get(i).getName().startsWith("set") && temp.get(i).getName().endsWith(onlyName)) {

                writeIn = true;
            }
        }

        if (readIn == true && writeIn == true)
            return "rw ";
        else if (readIn == true && writeIn == false)
            return "r ";
        else
            return "w ";
    }
}

Un autre cas avec la classe String

public static void main(String[] args) 
    {
        displayProperties(String.class);
    }

    public static void displayProperties(Class class){
        clazz.getDeclaredFields();

        Method[] methods = clazz.getDeclaredMethods();

        for(int ii = 0; ii<methods.length; ii++){
            System.out.println("Method Name: "+methods[ii].getName());
            System.out.println("Method Type: "+methods[ii].getReturnType());
            System.out.println("Method Pa: "+methods[ii].getParameterCount());
            System.out.println("Method Type: "+methods[ii].getReturnType());

        }
    }

Chargement à partir de XML avec réflexion

public static Object loadFromXml(String filePath) throws Exception {

        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        File newFile = new File(filePath);
        Document doc = builder.parse(newFile);
        Node root = doc.getFirstChild();

        return loadObjectElement(root);


    }
    /**
     * This method loads from an xml file and returns all the contents of the file as an object
     * @param root The node passed in to the method from which the "tree" gets a new level
     * @return all the contents of the xml file as an object
     * @throws Exception
     */
    public static Object loadObjectElement(Node root) throws Exception {
        //loads the root
        String studentClass = root.getAttributes().getNamedItem("class").getTextContent();
        Object newStudentObject = Class.forName(studentClass).newInstance();
        //gets the children nodes (may have text elements like \n)
        NodeList studentFieldList = root.getChildNodes();

        //iterates through the children nodes
        for (int i = 0; i < studentFieldList.getLength(); i++) {
            //checks to make sure the child node is not a text node
            if (studentFieldList.item(i).getNodeType() != Node.TEXT_NODE) {
                //checks if the current node does not have children
                if (studentFieldList.item(i).getChildNodes().getLength() == 0) {
                    //receives data of the current node
                    String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
                    String valueField = studentFieldList.item(i).getAttributes().getNamedItem("value").getTextContent();
                    Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);

                    //makes the field accessible
                    declaredFieldInClass.setAccessible(true);
                    //checks the field type
                    switch (declaredFieldInClass.getType().getSimpleName().toLowerCase()) {
                        case "integer":
                        case "int":
                            declaredFieldInClass.set(newStudentObject, Integer.valueOf(valueField));
                            break;
                        case "float":
                            declaredFieldInClass.set(newStudentObject, Float.valueOf(valueField));
                            break;
                        case "boolean":
                            declaredFieldInClass.set(newStudentObject, Boolean.valueOf(valueField));
                            break;
                        default:
                            declaredFieldInClass.set(newStudentObject, valueField);
                    }
                    declaredFieldInClass.setAccessible(false);
                } else {
                    //there are children in the current node
                    NodeList modulesObjectList = studentFieldList.item(i).getChildNodes();
                    String nameField = studentFieldList.item(i).getAttributes().getNamedItem("name").getTextContent();
                    Field declaredFieldInClass = newStudentObject.getClass().getDeclaredField(nameField);
                    List<Object> modules = new ArrayList<>();
                    //adds the modules into the array
                    for (int j = 0; j < modulesObjectList.getLength(); j++) {
                        if (modulesObjectList.item(j).getNodeType() != Node.TEXT_NODE) {
                            //recursively calls the the loadObjectElement method for any sub lists
                            modules.add(loadObjectElement(modulesObjectList.item(j)));
                        }
                    }
                    //sets the modules of the specific student that the method is working with
                    declaredFieldInClass.set(newStudentObject, modules);
                }
            }
        }
        return newStudentObject;
    }
 0
Author: ZapMeDo, 2017-05-12 05:57:39