Appeler des méthodes lors de l'exécution à l'aide de Java Reflection

1. Vue d'ensemble

Dans ce court article, nous examinerons rapidement comment appeler des méthodes au moment de l'exécution à l'aide de l'API Java Reflection .

2. Se préparer

Créons une classe simple que nous utiliserons pour les exemples qui suivent:

public class Operations { public double publicSum(int a, double b) { return a + b; } public static double publicStaticMultiply(float a, long b) { return a * b; } private boolean privateAnd(boolean a, boolean b) { return a && b; } protected int protectedMax(int a, int b) { return a > b ? a : b; } }

3. Obtention d'un objet méthode

Tout d'abord, nous devons obtenir un objet Method qui reflète la méthode que nous voulons invoquer. L' objet Class , représentant le type dans lequel la méthode est définie, fournit deux méthodes pour ce faire.

3.1. getMethod ()

Nous pouvons utiliser getMethod () pour trouver n'importe quelle méthode publique, qu'elle soit statique ou une instance définie dans la classe ou l'une de ses superclasses.

Il reçoit le nom de la méthode comme premier argument, suivi des types d'arguments de la méthode:

Method sumInstanceMethod = Operations.class.getMethod("publicSum", int.class, double.class); Method multiplyStaticMethod = Operations.class.getMethod( "publicStaticMultiply", float.class, long.class);

3.2. getDeclaredMethod ()

Nous pouvons utiliser getDeclaredMethod () pour obtenir n'importe quelle méthode définie dans la classe. Cela inclut les méthodes publiques, protégées, par défaut et même privées, mais exclut celles héritées.

Il reçoit les mêmes paramètres que getMethod () :

Method andPrivateMethod = Operations.class.getDeclaredMethod( "privateAnd", boolean.class, boolean.class);
Method maxProtectedMethod = Operations.class.getDeclaredMethod("protectedMax", int.class, int.class);

4. Appel de méthodes

Avec l' instance Method en place, nous pouvons maintenant appeler invoke () pour exécuter la méthode sous-jacente et obtenir l'objet retourné.

4.1. Méthodes d'instance

Pour appeler une méthode d'instance, le premier argument de invoke () doit être une instance de Method qui reflète la méthode appelée:

@Test public void givenObject_whenInvokePublicMethod_thenCorrect() { Method sumInstanceMethod = Operations.class.getMethod("publicSum", int.class, double.class); Operations operationsInstance = new Operations(); Double result = (Double) sumInstanceMethod.invoke(operationsInstance, 1, 3); assertThat(result, equalTo(4.0)); }

4.2. Méthodes statiques

Étant donné que ces méthodes ne nécessitent pas d'appeler une instance, nous pouvons passer null comme premier argument:

@Test public void givenObject_whenInvokeStaticMethod_thenCorrect() { Method multiplyStaticMethod = Operations.class.getDeclaredMethod( "publicStaticMultiply", float.class, long.class); Double result = (Double) multiplyStaticMethod.invoke(null, 3.5f, 2); assertThat(result, equalTo(7.0)); }

5. Accessibilité de la méthode

Par défaut, toutes les méthodes reflétées ne sont pas accessibles . Cela signifie que la JVM applique les contrôles de contrôle d'accès lors de leur appel.

Par exemple, si nous essayons d'appeler une méthode privée en dehors de sa classe de définition ou une méthode protégée depuis l'extérieur d'une sous-classe ou du package de sa classe, nous obtiendrons une IllegalAccessException :

@Test(expected = IllegalAccessException.class) public void givenObject_whenInvokePrivateMethod_thenFail() { Method andPrivateMethod = Operations.class.getDeclaredMethod( "privateAnd", boolean.class, boolean.class); Operations operationsInstance = new Operations(); Boolean result = (Boolean) andPrivateMethod.invoke(operationsInstance, true, false); assertFalse(result); } @Test(expected = IllegalAccessException.class) public void givenObject_whenInvokeProtectedMethod_thenFail() { Method maxProtectedMethod = Operations.class.getDeclaredMethod( "protectedMax", int.class, int.class); Operations operationsInstance = new Operations(); Integer result = (Integer) maxProtectedMethod.invoke(operationsInstance, 2, 4); assertThat(result, equalTo(4)); }

En appelant setAccesible (true) sur un objet de méthode reflété, la JVM supprime les vérifications de contrôle d'accès et nous permet d'appeler la méthode sans lever d'exception:

@Test public void givenObject_whenInvokePrivateMethod_thenCorrect() { // ... andPrivateMethod.setAccessible(true); // ... Boolean result = (Boolean) andPrivateMethod.invoke(operationsInstance, true, false); assertFalse(result); } @Test public void givenObject_whenInvokeProtectedMethod_thenCorrect() { // ... maxProtectedMethod.setAccessible(true); // ... Integer result = (Integer) maxProtectedMethod.invoke(operationsInstance, 2, 4); assertThat(result, equalTo(4)); }

6. Conclusion

Dans cet article rapide, nous avons vu comment appeler des méthodes d'instance et statiques d'une classe au moment de l'exécution via la réflexion. Nous avons également montré comment modifier l'indicateur accessible sur les objets de méthode reflétés pour supprimer les vérifications de contrôle d'accès Java lors de l'appel de méthodes privées et protégées.

Comme toujours, l'exemple de code peut être trouvé sur Github.