Qu'est-ce que la réflexion ?
La réflexion est une API qui permet, via un objet de type Class chargé dans la zone mémoire Heap, de créer une instance de la classe souhaitée et d'accéder aux champs et méthodes de l'instance, indépendamment des modificateurs d'accès.
Ici, une classe chargée signifie que le chargeur de classe de la JVM a terminé le chargement du fichier de classe et a créé un objet de type Classcontenant les informations de cette classe, puis l'a stocké dans la zone mémoire Heap. Il est important de noter que cela diffère de l'objet créé via le mot-clé new. Si vous ne comprenez pas bien l'objet de type Class, je vous conseille de consulter la documentation JDK de l'objet java.lang.class.
Méthode d'utilisation
Avant d'utiliser la réflexion, vous devez obtenir l'objet de type Class chargé dans la zone mémoire Heap. Il existe trois méthodes pour ce faire.
- Obtenir via Class.class
- Obtenir via Instance.getClass()
- Obtenir via Class.forName("NomDeLaClasse")
On peut constater que les instances de type Class obtenues via les trois méthodes sont identiques. Quelle que soit la méthode utilisée, la valeur de hachage est la même, vous pouvez donc les utiliser en fonction du contexte.
Maintenant, grâce à l'objet de type Class obtenu, nous pouvons créer une instance de la classe correspondante et accéder aux champs et aux méthodes de l'instance, indépendamment des modificateurs d'accès. Commençons par créer une instance de cette classe.
getConstructor() permet d'obtenir le constructeur et newInstance() permet de créer dynamiquement une instance de Member.
Enfin, accédons aux champs et aux méthodes de l'instance, indépendamment des modificateurs d'accès.
getDeclaredFileds() permet d'obtenir toutes les variables d'instance de la classe, get() permet de renvoyer la valeur du champ et set() permet de modifier la valeur du champ. Il est important de noter que pour accéder à un champ avec un modificateur d'accès private, vous devez passer true en argument à setAccessible().
De même, getDeclaredMethod() permet d'obtenir la méthode. Vous devez passer le nom de la méthode et le type des paramètres en arguments. De même, pour accéder à une méthode avec un modificateur d'accès private, vous devez définir l'argument de setAccessible() sur true. Enfin, invoke() permet d'appeler la méthode obtenue via l'API de réflexion.
Avantages et inconvénients
- Avantages
- Offre une flexibilité permettant de créer des instances de classe et d'accéder aux champs et méthodes, indépendamment des modificateurs d'accès, au moment de l'exécution.
- Inconvénients
- Compromission de l'encapsulation.
- Comme la création d'instances a lieu au moment de l'exécution, le type ne peut pas être vérifié au moment de la compilation.
- Comme la création d'instances a lieu au moment de l'exécution, il est difficile de comprendre le flux d'exécution concret.
- L'accès via la réflexion est plus lent que l'accès direct aux champs et méthodes. (Ce n'est pas toujours le cas.)
Raisons d'utilisation
L'API de réflexion permet d'accéder aux informations sur les classes pendant l'exécution et de manipuler les classes à volonté. On peut même manipuler les champs et les méthodes déclarés avec le modificateur d'accès private. Cela semble compromettre l'encapsulation, qui est un élément important de la conception orientée objet, et donne l'impression qu'il ne faut pas utiliser cette technique.
Dans le cas de petits programmes en console, le développeur peut facilement comprendre tous les objets et les relations de dépendance qui seront utilisés dans le programme au moment de la compilation. Cependant, dans le cas d'un développement à grande échelle, comme un framework, il est difficile de comprendre les nombreux objets et relations de dépendance. Dans ce cas, l'utilisation de la réflexion permet de créer des classes dynamiquement et d'établir des relations de dépendance.
Par exemple, si l'on prend l'exemple de Bean Factory de Spring, on constate que si l'on ajoute simplement les annotations @Controller, @Service et @Repository, Bean Factory crée et gère automatiquement les classes auxquelles ces annotations sont ajoutées. Le développeur n'a jamais spécifié ces classes à Bean Factory, mais cela est possible grâce à la réflexion. Au moment de l'exécution, il recherche les classes auxquelles ces annotations sont ajoutées et, si elles sont trouvées, il utilise la réflexion pour créer des instances de ces classes, injecter les champs nécessaires et les stocker dans Bean Factory.
Bien sûr, comme mentionné ci-dessus, l'encapsulation est compromise, il est donc préférable de l'utiliser uniquement lorsque cela est absolument nécessaire.
Commentaires0