Aufrufmethoden zur Laufzeit mit Java Reflection

1. Übersicht

In diesem kurzen Artikel sehen wir uns kurz an, wie Methoden zur Laufzeit mithilfe der Java Reflection-API aufgerufen werden .

2. Vorbereitungen

Erstellen wir eine einfache Klasse, die wir für die folgenden Beispiele verwenden:

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. Beziehen eines Method - Objekt

Zuerst müssen wir ein Methodenobjekt erhalten , das die Methode widerspiegelt, die wir aufrufen möchten. Das Class- Objekt, das den Typ darstellt, in dem die Methode definiert ist, bietet zwei Möglichkeiten, dies zu tun.

3.1. getMethod ()

Wir können getMethod () verwenden , um jede öffentliche Methode zu finden, sei es statisch oder eine Instanz, die in der Klasse oder einer ihrer Oberklassen definiert ist.

Es erhält den Methodennamen als erstes Argument, gefolgt von den Argumenttypen der Methode:

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

3.2. getDeclaredMethod ()

Wir können getDeclaredMethod () verwenden , um jede in der Klasse definierte Methode abzurufen . Dies umfasst öffentliche, geschützte, Standardzugriffs- und sogar private Methoden, schließt jedoch geerbte Methoden aus.

Es erhält die gleichen Parameter wie getMethod () :

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

4. Methoden aufrufen

Mit der vorhandenen Methodeninstanz können wir jetzt invoke () aufrufen , um die zugrunde liegende Methode auszuführen und das zurückgegebene Objekt abzurufen.

4.1. Instanzmethoden

Um eine Instanzmethode aufzurufen, muss das erste Argument , das aufgerufen wird () , eine Instanz der Methode sein , die die aufgerufene Methode widerspiegelt:

@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. Statische Methoden

Da für diese Methoden keine Instanz aufgerufen werden muss, können wir als erstes Argument null übergeben :

@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. Zugänglichkeit der Methode

Standardmäßig ist nicht auf alle reflektierten Methoden zugegriffen . Dies bedeutet, dass die JVM beim Aufrufen Zugriffskontrollprüfungen erzwingt.

Wenn wir beispielsweise versuchen, eine private Methode außerhalb ihrer definierenden Klasse oder eine geschützte Methode außerhalb einer Unterklasse oder ihres Klassenpakets aufzurufen , erhalten wir eine 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)); }

Durch Aufrufen von setAccesible (true) für ein reflektiertes Methodenobjekt unterdrückt die JVM die Zugriffssteuerungsprüfungen und ermöglicht es uns, die Methode aufzurufen, ohne eine Ausnahme auszulösen :

@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. Fazit

In diesem kurzen Artikel haben wir gesehen, wie Instanz- und statische Methoden einer Klasse zur Laufzeit durch Reflektion aufgerufen werden. Wir haben auch gezeigt, wie das Zugriffsflag für die reflektierten Methodenobjekte geändert wird, um Java-Zugriffssteuerungsprüfungen beim Aufrufen privater und geschützter Methoden zu unterdrücken.

Der Beispielcode ist wie immer auf Github zu finden.