2011-01-22 3 views
47

Vorrei invocare un metodo statico privato. Ho il suo nome Ho sentito che può essere fatto usando il meccanismo di riflessione Java. Come posso farlo?Come si richiama un metodo statico privato mediante reflection (Java)?

MODIFICA: Un problema che ho riscontrato durante il tentativo di richiamare il metodo è come specificare il tipo del suo argomento. Il mio metodo riceve un argomento e il suo tipo è Map. Quindi non posso fare Map<User, String>.TYPE (In fase di esecuzione non esiste una cosa come Map a causa della cancellazione del tipo Java). C'è un altro modo per ottenere il metodo?

+1

prova 'MyClass.class.getDeclaredMethod ("myMethod", Map.class);' per il vostro caso – Cratylus

+0

Stranamente il generico le informazioni sul metodo sono ancora disponibili in fase di esecuzione. 'Method.getGenericParameterTypes' –

risposta

79

Supponiamo di voler chiamare MyClass.myMethod (int x);

Method m = MyClass.class.getDeclaredMethod("myMethod", Integer.TYPE); 
m.setAccessible(true); //if security settings allow this 
Object o = m.invoke(null, 23); //use null if the method is static 
+0

Grazie. Il mio metodo riceve un parametro e il suo tipo è Map . Pertanto non posso fare "Map .TYPE". C'è un altro modo per ottenere il metodo? – snakile

+6

@snakile: prova 'MyClass.class.getDeclaredMethod (" myMethod ", Map.class);' per il tuo caso – Cratylus

+3

Tutto ciò che mi è stato insegnato in Università era una bugia ... – rsy

0
Object insecure; //This needs to be an initialized reference 

Class c = insecure.getClass(); 
Method m = c.getMethod(name, parameterTypes); //Fill the name and types in 
m.setAccessible(true); 
m.invoke(insecure, parameters); //Fill in the parameters you would like 

ci sono un certo numero di eccezioni controllate che possono essere gettati. Sia parameterTypes sia i parametri sono argomenti di ellisse (lunghezza variabile), riempili come necessario. La specifica JVM ha una convenzione di chiamata fortemente tipizzata, quindi è necessario conoscere i tipi di parametro.

Con ciò detto, a meno che non si stia scrivendo una sorta di contenitore di applicazioni, contenitore di componenti server, sistema simile a RMI o langauge basato su JVM, si dovrebbe evitare di farlo.

9

Invoke principale da reflection tutorial

import java.lang.reflect.InvocationTargetException; 
import java.lang.reflect.Method; 
import java.util.Arrays; 

public class InvokeMain { 
    public static void main(String... args) { 
    try { 
     Class<?> c = Class.forName(args[0]); 
     Class[] argTypes = new Class[] { String[].class }; 
     Method main = c.getDeclaredMethod("main", argTypes); 
     String[] mainArgs = Arrays.copyOfRange(args, 1, args.length); 
     System.out.format("invoking %s.main()%n", c.getName()); 
     main.invoke(null, (Object)mainArgs); 

     // production code should handle these exceptions more gracefully 
    } catch (ClassNotFoundException x) { 
     x.printStackTrace(); 
    } catch (NoSuchMethodException x) { 
     x.printStackTrace(); 
    } catch (IllegalAccessException x) { 
     x.printStackTrace(); 
    } catch (InvocationTargetException x) { 
     x.printStackTrace(); 
    } 
    } 
} 
2

No, non si può dire Map<K,V>.class. Questo a causa della cancellazione del tipo . Al momento dell'esecuzione, non esiste una cosa del genere.

Per fortuna, è possibile dire semplicemente vecchio Map.class. È lo stesso in fase di runtime.

Se gli avvertimenti ti infastidiscono, cerca altre domande relative ai generici e alla cancellazione dei tipi, qui c'è una grande quantità di informazioni sull'argomento.

+0

+1 per indicare la cancellazione del tipo – snakile

1

Io uso un singolo metodo che incapsula ottenendo il metodo di destinazione e quindi invocandolo. Probabilmente ha alcune limitazioni, ovviamente. Ecco il metodo messo in una classe e il suo test JUnit:

public class Invoker { 
/** 
* Get method and invoke it. 
* 
* @author jbetancourt 
* 
* @param name of method 
* @param obj Object to invoke the method on 
* @param types parameter types of method 
* @param args to method invocation 
* @return return value 
* @throws Exception for unforseen stuff 
*/ 
public static final <T> Object invokeMethod(final String name, final T obj, 
    final Class<?>[] types, final Object... args) throws Exception { 

    Method method = obj.getClass().getDeclaredMethod(name, types); 
    method.setAccessible(true); 
    return method.invoke(obj, args); 
} 

/** 
* Embedded JUnit tests. 
*/ 
@RunWith(JUnit4.class) 
public static class InvokerTest { 
    /** */ 
    @Test 
    public void testInvoke() throws Exception { 
     class TestTarget { 
      private String hello() { 
       return "Hello world!"; 
      } 
     } 

     String actual = (String) Invoker.invokeMethod("hello", 
       new TestTarget(), new Class<?>[] {}); 
     String expected = "Hello world!"; 
     assertThat(actual, is(expected)); 

    } 
} 

}