Comment savoir par réflexion quel est le nom de chaîne de la méthode?
Par exemple donné:
class Car{
public void getFoo(){
}
}
Je veux obtenir la chaîne "getFoo", quelque chose comme ceci:
Car.getFoo.toString() == "getFoo" // TRUE
Comme les méthodes ne sont pas des objets elles-mêmes, elles n'ont pas de propriétés directes (contrairement aux fonctions de première classe dans des langages comme JavaScript).
Le plus près que vous puissiez faire est d'appeler Car.class.getMethods()
Car.class
est un objet Class
que vous pouvez utiliser pour appeler l'une des méthodes de réflexion.
Cependant, pour autant que je sache, une méthode n'est pas capable de s'identifier.
Vous pouvez obtenir la chaîne comme ceci:
Car.class.getDeclaredMethods()[0].getName();
C'est pour le cas d'une seule méthode dans votre classe. Si vous voulez parcourir toutes les méthodes déclarées, vous devrez parcourir le tableau renvoyé par Car.class.getDeclaredMethods()
:
for (Method method : Car.class.getDeclaredMethods()) {
String name = method.getName();
}
Vous devez utiliser getDeclaredMethods()
si vous souhaitez les afficher tous. getMethods()
ne renverra que public methods.
Et enfin, si vous voulez voir le nom de la méthode en cours d’exécution, vous devez utiliser le code suivant:
Thread.currentThread().getStackTrace()[1].getMethodName();
Cela obtiendra une trace de pile pour le thread actuel et renverra le nom de la méthode sur son sommet.
Donc, vous voulez obtenir le nom de la méthode en cours d'exécution? Voici une façon un peu moche de faire cela:
Exception e = new Exception();
e.fillInStackTrace();
String methodName = e.getStackTrace()[0].getMethodName();
essaye ça,
import Java.lang.reflect.*;
public class DumpMethods {
public static void main(String args[]) {
try {
Class c = Class.forName(args[0]);
Method m[] = c.getDeclaredMethods();
for (int i = 0; i < m.length; i++)
System.out.println(m[i].toString());
} catch (Throwable e) {
System.err.println(e);
}
}
}
Avec Java 8, vous pouvez le faire avec quelques lignes de code (presque) sans aucune bibliothèque supplémentaire. La clé est de convertir votre méthode en une expression lambda sérialisable. Par conséquent, vous pouvez simplement définir une interface simple comme celle-ci:
@FunctionalInterface
public interface SerializableFunction<I, O> extends Function<I, O>, Serializable {
// Combined interface for Function and Serializable
}
Maintenant, nous devons convertir notre expression lambda en un objet SerializedLambda
. Apparemment, Oracle ne veut pas vraiment que nous fassions cela, alors prenez ceci avec un grain de sel ... Comme la méthode requise est privée, nous devons l'invoquer à l'aide de réflexions:
private static final <T> String nameOf(SerializableFunction<T, ?> lambda) {
Method findMethod = ReflectionUtils.findMethod(lambda.getClass(), "writeReplace");
findMethod.setAccessible(true);
SerializedLambda invokeMethod = (SerializedLambda) ReflectionUtils.invokeMethod(findMethod, lambda);
return invokeMethod.getImplMethodName();
}
J'utilise la classe Springs ReflectionUtils
ici pour plus de simplicité, mais vous pouvez bien sûr le remplacer par une boucle manuelle dans toutes les superclasses et utiliser getDeclaredMethod
pour trouver la méthode writeReplace
.
Et ça y est déjà, vous pouvez maintenant l'utiliser comme ceci:
@Test
public void testNameOf() throws Throwable {
assertEquals("getName", nameOf(MyClassTest::getName));
}
Je n'ai pas vérifié cela avec le système de modules Java 9s, alors il serait peut-être plus difficile de le faire avec des versions plus récentes de Java ...
Attendez, puisque vous connaissez déjà le nom de la méthode, ne pouvez-vous pas simplement le taper sous forme de chaîne?
Au lieu de (pseudo) Class.methodName.toString()
, utilisez simplement "methodName
".
Sinon, vous pouvez utiliser Class#getDeclaredMethods()
pour obtenir toutes les méthodes d'une classe.
Regardez dans ce fil:
Obtenir le nom de la méthode en cours d'exécution
Il offre quelques solutions supplémentaires - par exemple:
String name = new Object(){}.getClass().getEnclosingMethod().getName();