Chiamare i metodi in fase di runtime utilizzando Java Reflection

1. Panoramica

In questo breve articolo, daremo una rapida occhiata a come invocare metodi in fase di esecuzione utilizzando l'API Java Reflection .

2. Prepararsi

Creiamo una semplice classe che useremo per gli esempi che seguono:

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. Ottenere un oggetto metodo

Per prima cosa, dobbiamo ottenere un oggetto Method che rifletta il metodo che vogliamo invocare. L' oggetto Class , che rappresenta il tipo in cui è definito il metodo, fornisce due modi per farlo.

3.1. getMethod ()

Possiamo usare getMethod () per trovare qualsiasi metodo pubblico, statico o istanza definita nella classe o in una delle sue superclassi.

Riceve il nome del metodo come primo argomento, seguito dai tipi di argomenti del metodo:

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

3.2. getDeclaredMethod ()

Possiamo usare getDeclaredMethod () per ottenere qualsiasi metodo definito nella classe. Ciò include metodi pubblici, protetti, di default e persino privati, ma esclude quelli ereditati.

Riceve gli stessi parametri di getMethod () :

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

4. Invocare metodi

Con l' istanza di Method in posizione, ora possiamo chiamare invoke () per eseguire il metodo sottostante e ottenere l'oggetto restituito.

4.1. Metodi di istanza

Per invocare un metodo di istanza, il primo argomento di invoke () deve essere un'istanza di Method che riflette il metodo richiamato:

@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. Metodi statici

Poiché questi metodi non richiedono la chiamata di un'istanza, possiamo passare null come primo argomento:

@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à del metodo

Per impostazione predefinita, non tutti i metodi riflessi sono accessibili . Ciò significa che la JVM applica i controlli di controllo degli accessi quando li richiama.

Ad esempio, se proviamo a chiamare un metodo privato al di fuori della sua classe di definizione o un metodo protetto dall'esterno di una sottoclasse o del pacchetto della sua classe, otterremo un'eccezione 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)); }

Chiamando setAccesible (true) su un oggetto del metodo riflesso, la JVM sopprime i controlli di controllo dell'accesso e ci consente di richiamare il metodo senza generare un'eccezione:

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

In questo breve articolo, abbiamo visto come chiamare metodi statici e istanza di una classe in fase di esecuzione tramite la reflection. Abbiamo anche mostrato come modificare il flag accessibile sugli oggetti del metodo riflesso per sopprimere i controlli di controllo dell'accesso Java quando si invocano metodi privati ​​e protetti.

Come sempre, il codice di esempio può essere trovato su Github.