Je voudrais invoquer une méthode statique privée. J'ai son nom. J'ai entendu dire que cela peut être fait en utilisant Java mécanisme de réflexion. Comment puis-je le faire?
EDIT: Un problème que j'ai rencontré en essayant d'appeler la méthode est de savoir comment spécifier le type de son argument. Ma méthode reçoit un argument et son type est Map. Je ne peux donc pas faire Map<User, String>.TYPE
(Au moment de l'exécution, Map n'existe pas à cause de Java Type erasure). Existe-t-il un autre moyen d'obtenir la méthode?
Disons que vous voulez appeler 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
Invoke main from tutoriel de réflexion
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();
}
}
}
Non, vous ne pouvez pas dire Map<K,V>.class
. C'est à cause de effacement de type. À l'exécution, il n'y a rien de tel.
Heureusement, vous pouvez dites simplement vieux Map.class
. C'est tout de même à l'exécution.
Si les avertissements vous dérangent, recherchez d'autres questions liées aux génériques et à l'effacement de type, il y a une foule d'informations sur le sujet ici.
J'utilise une seule méthode qui encapsule l'obtention de la méthode cible, puis son invocation. Il y a probablement des limites, bien sûr. Voici la méthode mise dans une classe et son 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));
}
}
}
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
Il existe un certain nombre d'exceptions vérifiées qui peuvent être levées. Les parametypes et les paramètres sont des arguments d'ellipse (longueur variable), remplissez-les si nécessaire. La JVM par spécification a une convention d'appel fortement typée, vous devez donc connaître les types de paramètres.
Cela dit, à moins que vous n'écriviez une sorte de conteneur d'application, de conteneur de composant serveur, de système similaire à RMI ou de langage basé sur JVM, vous devez éviter de le faire.