J'ai besoin de trouver l'appelant d'une méthode. Est-il possible d'utiliser stacktrace ou réflexion?
java
stack-trace
Sathish
la source
la source
DontNameYourMethodFooException
si la méthode d'appel est nommée foo.Réponses:
Selon les Javadocs:
A
StackTraceElement
agetClassName()
,getFileName()
,getLineNumber()
etgetMethodName()
.Vous devrez expérimenter pour déterminer quel index vous voulez (probablement
stackTraceElements[1]
ou[2]
).la source
Une solution alternative peut être trouvée dans un commentaire à cette demande d'amélioration . Il utilise la
getClassContext()
méthode d'un personnaliséSecurityManager
et semble être plus rapide que la méthode de trace de pile.Le programme suivant teste la vitesse des différentes méthodes suggérées (le bit le plus intéressant est dans la classe interne
SecurityManagerMethod
):Un exemple de la sortie de mon MacBook Intel Core 2 Duo 2,4 GHz exécutant Java 1.6.0_17:
La méthode de réflexion interne est beaucoup plus rapide que les autres. Obtenir une trace de pile à partir d'une nouvelle création
Throwable
est plus rapide que de la récupérer à partir du courantThread
. Et parmi les moyens non internes de trouver la classe d'appel, la coutumeSecurityManager
semble être la plus rapide.Mise à jour
Comme le souligne lyomi dans ce commentaire, la
sun.reflect.Reflection.getCallerClass()
méthode a été désactivée par défaut dans Java 7 mise à jour 40 et supprimée complètement dans Java 8. Pour en savoir plus à ce sujet, consultez la base de données de bogues Java .Update 2
Comme l' a constaté zammbi , Oracle a été contraint d' annuler la modification qui a supprimé le
sun.reflect.Reflection.getCallerClass()
. Il est toujours disponible dans Java 8 (mais il est obsolète).Mise à jour 3
3 ans après: mise à jour du timing avec la JVM actuelle.
la source
On dirait que vous essayez d'éviter de passer une référence à
this
dans la méthode. Passerthis
est bien mieux que de trouver l'appelant via la trace de pile actuelle. Le refactoring vers une conception plus OO est encore mieux. Vous ne devriez pas avoir besoin de connaître l'appelant. Passez un objet de rappel si nécessaire.la source
LoggerFactory.getLogger(MyClass.class)
où je n'ai pas eu à passer dans le littéral de la classe. C'est encore rarement la bonne chose à faire.INotifyPropertyChanged
interface .NET . Bien que cet exemple spécifique ne soit pas en Java, le même problème peut se manifester lorsque vous essayez de modéliser des champs / getters sous forme de chaînes pour Reflection.Java 9 - JEP 259: API Stack-Walking
JEP 259 fournit une API standard efficace pour la marche de pile qui permet un filtrage facile et un accès paresseux aux informations dans les traces de pile. Avant l'API Stack-Walking, les moyens courants d'accéder aux cadres de pile étaient les suivants:
L'utilisation de ces API est généralement inefficace:
Afin de trouver la classe de l'appelant immédiat, obtenez d'abord un
StackWalker
:Ensuite, appelez le
getCallerClass()
:ou
walk
lesStackFrame
s et obtenez le premier précédentStackFrame
:la source
Oneliner :
Notez que vous devrez peut-être remplacer le 2 par 1.
la source
Cette méthode fait la même chose mais un peu plus simplement et peut-être un peu plus performante et dans le cas où vous utilisez la réflexion, elle saute ces images automatiquement. Le seul problème est qu'il peut ne pas être présent dans les JVM non Sun, bien qu'il soit inclus dans les classes d'exécution de JRockit 1.4 -> 1.6. (Le fait est que ce n'est pas une classe publique ).
En ce qui concerne la
realFramesToSkip
valeur, les versions VM de Sun 1.5 et 1.6java.lang.System
, il existe une méthode protégée par package appelée getCallerClass () qui appellesun.reflect.Reflection.getCallerClass(3)
, mais dans ma classe utilitaire d'aide, j'ai utilisé 4 car il y a le cadre ajouté de la classe helper invocation.la source
Par exemple, si vous essayez d'obtenir la ligne de méthode d'appel à des fins de débogage, vous devez dépasser la classe Utility dans laquelle vous
codez ces méthodes statiques: (ancien code java1.4, juste pour illustrer une utilisation potentielle de StackTraceElement)
la source
Je l'ai déjà fait auparavant. Vous pouvez simplement créer une nouvelle exception et récupérer la trace de pile dessus sans la lancer, puis examiner la trace de pile. Comme le dit l'autre réponse, c'est extrêmement coûteux - ne le faites pas en boucle.
Je l'ai déjà fait pour un utilitaire de journalisation sur une application où les performances importaient peu (les performances importent rarement, en fait - tant que vous affichez le résultat d'une action telle qu'un clic de bouton rapidement).
C'était avant que vous puissiez obtenir la trace de la pile, les exceptions avaient juste .printStackTrace () donc j'ai dû rediriger System.out vers un flux de ma propre création, puis (new Exception ()). PrintStackTrace (); Redirigez System.out vers l'arrière et analysez le flux. Truc amusant.
la source
la source
Voici une partie du code que j'ai créé sur la base des conseils montrés dans cette rubrique. J'espère que cela aide.
(N'hésitez pas à faire des suggestions pour améliorer ce code, veuillez me le dire)
Le compteur:
Et l'objet:
la source
OU
la source
utilisez cette méthode: -
L'appelant de l'exemple de méthode Code est ici: -
la source