2010-02-19 4 views
1

Est-il possible d'obtenir des informations sur la classe qui invoque l'autre?
Obtenir des informations sur l'appel de la classe


class Bar{ 
    public Bar{} 

    public String getInvokingClassInfo(){ 
     return "..."; 
    } 
} 

class Foo{ 
    public Foo(){ 
     Bar bar = new Bar(); 
     System.out.println("Invoking class is: "+bar.getInvokingClassInfo()); 
    } 
} 

Comment se rendre à la place:


System.out.println(bar.getInvokingClassInfo()); 

informations sur les classes que l'invocation (Foo) celui-ci (Bar):

Invoking class: Foo

Répondre

8
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 
String callerClassName = stackTrace[index].getClassName(); 

Cela devient la stacktrace pour le thread actuel. Comme il est indiqué dans les commentaires, il y a des différences de mise en œuvre, de sorte que si vous craignez que tel, vous pouvez mettre en œuvre quelque chose comme ceci:

    boucle
  • à travers le réseau StackTraceElement (en utilisant une variable compteur déclarée en dehors de la boucle)
  • chaque fois que vous rencontrer le nom de classe actuelle et la méthode actuelle, break
  • obtenir le suivant élément du tableau - il sera l'invocateur. (C'est ce que index signifie dans le code ci-dessus)
  • si le ci-dessus ne fournit pas d'informations pertinentes que vous pouvez toujours revenir à new Exception().getStackTrace()
+0

Ce n'est pas correct. Le premier élément (s) du tableau est la méthode getStackTrace et potentiellement d'autres méthodes invoquées en interne par getStackTrace(). Différentes versions de la VM de Sun montrent un comportement différent ici. Dans 1.5.0_15, les deux premiers éléments sont 'Thread.dumpThreads' et' Thread.getStackTrace' tandis que dans 1.5.0_18, le premier élément est 'Thread.getStackTrace'. – jarnbjo

+0

Il fonctionne parfaitement pour mon but:

 public String getInvokingClassInfo(){ StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); return stackTrace[stackTrace.length-2].getClassName(); }  
Je sais que c'est un peu niché mais pour le débogage c'est ok. – kospiotr

+0

oui, mis à jour. Cela entraîne simplement l'incrémentation de l'index. – Bozho

3

Le meilleur (si crispé et laid) solution que je pouvais penser serait soit de lancer une exception à l'intérieur de Bar et de l'attraper tout de suite, puis d'extraire les informations de l'appelant de sa trace de pile.

Mise à jour basée sur les commentaires des autres: vous n'avez même pas besoin de jeter et attraper l'exception, new Exception().getStackTrace() fera l'affaire.

+0

pas _that_ moche en fait - il fait partie (bien que pas dans le cas commun) de l'implémentation de Thread.getStackTrace() – Bozho

+0

C'est je pense plus de manière correcte que la précédente mais j'imagine que beaucoup classess étendent la classe Bar et la classe étendue se produit dans beaucoup d'endroits, donc ... beaucoup essayent/attrapent des clausures, beaucoup de lignes de nouveau code. Nous pourrions concorder des proxies mais cela vaut-il la peine? – kospiotr

+0

@kospiotr Si vous voulez obtenir des informations sur l'appelant dans beaucoup de méthodes différentes dans 'Bar' et ses sous-classes, vous pouvez le faire en implémentant cette solution dans une seule méthode protégée de' Bar', puis en l'appelant depuis toutes les autres méthodes . Bien sûr, l'analyseur de traces de pile devrait commencer à chercher à partir du 3e élément du tableau, et non du 2e (s'il y a suffisamment d'éléments, bien sûr). –

2

La manière la plus robuste que je puisse imaginer est de passer "this" comme argument à B depuis l'intérieur de A. Alors B peut regarder l'objet et en imprimer la classe. Tout ce qui se joue des traces de pile repose sur des choses dont le fonctionnement n'est pas garanti. L'approche "pass-this" sera.

0

La I façon la plus simple trouvée était de créer une classe suivante:

private static class ClassLocator extends SecurityManager { 
    public static Class<?> getCallerClass() {  
     return new ClassLocator().getClassContext()[2]; 
    } 
} 

Comme l'API Référence dit:

« protégées de classe [] getClassContext() Renvoie la pile d'exécution en cours comme un tableau La longueur du tableau est le nombre de méthodes sur la pile d'exécution: l'élément à l'index 0 est la classe de la méthode en cours d'exécution, l'élément à l'index 1 est la classe de l'appelant, etc. "

http://docs.oracle.com/javase/7/docs/api/java/lang/SecurityManager.html#getClassContext()

Questions connexes