Comment trouver l'appelant d'une méthode utilisant stacktrace ou réflexion?


392

J'ai besoin de trouver l'appelant d'une méthode. Est-il possible d'utiliser stacktrace ou réflexion?


5
Je me demandais juste, mais pourquoi auriez-vous besoin de faire cela?
Juliet

2
J'ai une classe Parent (modèle MVC) avec un événement notifier et seuls les setters de mes sous-classes appellent cette méthode. je ne veux pas jeter mon code avec un argument redondant. Je préfère laisser la méthode dans la classe parente comprendre le setter qui l'a appelée.
Sathish

30
@Sathish On dirait que vous devriez repenser ce design
krosenvold

7
@Juliet Dans le cadre de la refactorisation d'un gros bloc de code, j'ai récemment changé une méthode qui est utilisée par beaucoup de choses. Il existe une certaine façon de détecter si le code utilise correctement la nouvelle méthode, donc j'imprimais la classe et le numéro de ligne qui l'appelaient dans ces cas. En dehors de la journalisation, je ne vois aucun objectif réel pour quelque chose comme ça. Bien que je veuille écrire des API maintenant qui lancent un DontNameYourMethodFooExceptionsi la méthode d'appel est nommée foo.
Cruncher

5
Je trouve être en mesure d'obtenir l'appelant de ma méthode un outil de débogage inestimable: c'est ainsi qu'une recherche sur le Web m'a amené ici. Si ma méthode est appelée de plusieurs endroits, est-elle appelée du bon endroit au bon moment? En dehors du débogage ou de la journalisation, l'utilité est probablement au mieux limitée, comme le mentionne @Cruncher.
Ogre Psalm33

Réponses:


413
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace()

Selon les Javadocs:

Le dernier élément du tableau représente le bas de la pile, qui est l'appel de méthode le moins récent de la séquence.

A StackTraceElementa getClassName(), getFileName(), getLineNumber()et getMethodName().

Vous devrez expérimenter pour déterminer quel index vous voulez (probablement stackTraceElements[1]ou [2]).


7
Je dois noter que getStackTrace () crée toujours une exception, donc ce n'est pas vraiment plus rapide - juste plus pratique.
Michael Myers

42
Notez que cette méthode ne vous donnera pas l'appelant, mais uniquement le type de l'appelant . Vous n'aurez pas de référence à l'objet appelant votre méthode.
Joachim Sauer

3
Juste une remarque, mais sur une JVM Thread.currentThread () 1.5. GetStackTrace () semble être beaucoup plus lent que la création d'une nouvelle Exception () (environ 3 fois plus lente). Mais comme déjà indiqué, vous ne devriez pas utiliser de code comme celui-ci de toute façon dans une zone critique pour les performances. ;) Une JVM 1.6 ne semble être que 10% plus lente et, comme l'a dit Software Monkey, elle exprime mieux l'intention que la "nouvelle exception".
GaZ

21
@Eelco Thread.currentThread () est bon marché. Thread.getStackTrace () coûte cher car, contrairement à Throwable.fillInStackTrace (), il n'y a aucune garantie que la méthode est appelée par le même thread qu'elle examine, la JVM doit donc créer un "point de sécurité" - verrouillant le tas et la pile. Voir ce rapport de bogue: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
David Moles

7
@JoachimSauer connaissez-vous un moyen d'obtenir une référence à l'objet appelant la méthode?
jophde

216

Une solution alternative peut être trouvée dans un commentaire à cette demande d'amélioration . Il utilise la getClassContext()méthode d'un personnalisé SecurityManageret 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):

/**
 * Test the speed of various methods for getting the caller class name
 */
public class TestGetCallerClassName {

  /**
   * Abstract class for testing different methods of getting the caller class name
   */
  private static abstract class GetCallerClassNameMethod {
      public abstract String getCallerClassName(int callStackDepth);
      public abstract String getMethodName();
  }

  /**
   * Uses the internal Reflection class
   */
  private static class ReflectionMethod extends GetCallerClassNameMethod {
      public String getCallerClassName(int callStackDepth) {
          return sun.reflect.Reflection.getCallerClass(callStackDepth).getName();
      }

      public String getMethodName() {
          return "Reflection";
      }
  }

  /**
   * Get a stack trace from the current thread
   */
  private static class ThreadStackTraceMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return Thread.currentThread().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Current Thread StackTrace";
      }
  }

  /**
   * Get a stack trace from a new Throwable
   */
  private static class ThrowableStackTraceMethod extends GetCallerClassNameMethod {

      public String getCallerClassName(int callStackDepth) {
          return new Throwable().getStackTrace()[callStackDepth].getClassName();
      }

      public String getMethodName() {
          return "Throwable StackTrace";
      }
  }

  /**
   * Use the SecurityManager.getClassContext()
   */
  private static class SecurityManagerMethod extends GetCallerClassNameMethod {
      public String  getCallerClassName(int callStackDepth) {
          return mySecurityManager.getCallerClassName(callStackDepth);
      }

      public String getMethodName() {
          return "SecurityManager";
      }

      /** 
       * A custom security manager that exposes the getClassContext() information
       */
      static class MySecurityManager extends SecurityManager {
          public String getCallerClassName(int callStackDepth) {
              return getClassContext()[callStackDepth].getName();
          }
      }

      private final static MySecurityManager mySecurityManager =
          new MySecurityManager();
  }

  /**
   * Test all four methods
   */
  public static void main(String[] args) {
      testMethod(new ReflectionMethod());
      testMethod(new ThreadStackTraceMethod());
      testMethod(new ThrowableStackTraceMethod());
      testMethod(new SecurityManagerMethod());
  }

  private static void testMethod(GetCallerClassNameMethod method) {
      long startTime = System.nanoTime();
      String className = null;
      for (int i = 0; i < 1000000; i++) {
          className = method.getCallerClassName(2);
      }
      printElapsedTime(method.getMethodName(), startTime);
  }

  private static void printElapsedTime(String title, long startTime) {
      System.out.println(title + ": " + ((double)(System.nanoTime() - startTime))/1000000 + " ms.");
  }
}

Un exemple de la sortie de mon MacBook Intel Core 2 Duo 2,4 GHz exécutant Java 1.6.0_17:

Reflection: 10.195 ms.
Current Thread StackTrace: 5886.964 ms.
Throwable StackTrace: 4700.073 ms.
SecurityManager: 1046.804 ms.

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 Throwableest plus rapide que de la récupérer à partir du courant Thread. Et parmi les moyens non internes de trouver la classe d'appel, la coutume SecurityManagersemble ê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.

> java -version
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
> java TestGetCallerClassName
Reflection: 0.194s.
Current Thread StackTrace: 3.887s.
Throwable StackTrace: 3.173s.
SecurityManager: 0.565s.

5
Oui, ça ressemble à ça. Mais notez que le timing que je donne dans l'exemple est pour un million d'appels - donc, selon la façon dont vous l'utilisez, cela pourrait ne pas être un problème.
Johan Kaving

1
Pour moi, supprimer la réflexion de mon projet a entraîné une augmentation de la vitesse de 10 fois.
Kevin Parker

1
Oui, la réflexion en général est lente (voir par exemple stackoverflow.com/questions/435553/java-reflection-performance ), mais dans ce cas spécifique, l'utilisation de la classe interne sun.reflect.Reflection est la plus rapide.
Johan Kaving

1
En fait, il n'en a pas besoin. Vous pouvez le vérifier en modifiant le code ci-dessus pour imprimer le nom de classe retourné (et je suggère de réduire le nombre de boucles à 1). Vous verrez que toutes les méthodes renvoient le même className - TestGetCallerClassName.
Johan Kaving

1
getCallerClass est obsolète et sera supprimé dans 7u40 .. triste :(
lyomi

36

On dirait que vous essayez d'éviter de passer une référence à thisdans la méthode. Passer thisest 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.


6
++ Connaître l'appelant représente trop d'informations. Si vous devez, vous pouvez passer dans une interface, mais il y a de fortes chances qu'une refactorisation majeure soit nécessaire. @satish devrait publier son code et amusons-nous :)
Bill K

15
Il existe des raisons valables de vouloir le faire. J'ai eu quelques occasions où je l'ai trouvé utile lors de tests par exemple.
Eelco

2
@chillenious je sais :) Je l'ai fait moi-même pour créer une méthode comme 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.
Craig P. Motlin

6
C'est un bon conseil en général, mais cela ne répond pas à la question.
Navin

1
Un exemple concret du moment où il pourrait être la bonne décision de conception pour obtenir des informations sur l'appelant est lors de la mise en œuvre de l' INotifyPropertyChangedinterface .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.
Chris Kerekes

31

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:

Throwable::getStackTraceet Thread::getStackTracerenvoyer un tableau d' StackTraceElementobjets, qui contiennent le nom de classe et le nom de méthode de chaque élément de trace de pile.

SecurityManager::getClassContextest une méthode protégée, qui permet à une SecurityManagersous - classe d'accéder au contexte de classe.

sun.reflect.Reflection::getCallerClassMéthode interne JDK que vous ne devriez pas utiliser de toute façon

L'utilisation de ces API est généralement inefficace:

Ces API nécessitent que la machine virtuelle capture avec empressement un instantané de la pile entière , et elles renvoient des informations représentant la pile entière. Il n'y a aucun moyen d'éviter le coût de l'examen de toutes les trames si l'appelant ne s'intéresse qu'aux premières trames de la pile.

Afin de trouver la classe de l'appelant immédiat, obtenez d'abord un StackWalker:

StackWalker walker = StackWalker
                           .getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE);

Ensuite, appelez le getCallerClass():

Class<?> callerClass = walker.getCallerClass();

ou walkles StackFrames et obtenez le premier précédent StackFrame:

walker.walk(frames -> frames
      .map(StackWalker.StackFrame::getDeclaringClass)
      .skip(1)
      .findFirst());

15

Oneliner :

Thread.currentThread().getStackTrace()[2].getMethodName()

Notez que vous devrez peut-être remplacer le 2 par 1.


10

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 ).

sun.reflect.Reflection

    /** Returns the class of the method <code>realFramesToSkip</code>
        frames up the stack (zero-based), ignoring frames associated
        with java.lang.reflect.Method.invoke() and its implementation.
        The first frame is that associated with this method, so
        <code>getCallerClass(0)</code> returns the Class object for
        sun.reflect.Reflection. Frames associated with
        java.lang.reflect.Method.invoke() and its implementation are
        completely ignored and do not count toward the number of "real"
        frames skipped. */
    public static native Class getCallerClass(int realFramesToSkip);

En ce qui concerne la realFramesToSkipvaleur, les versions VM de Sun 1.5 et 1.6 java.lang.System, il existe une méthode protégée par package appelée getCallerClass () qui appelle sun.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.


16
L'utilisation de classes d'implémentation JVM est une très mauvaise idée.
Lawrence Dol

7
C'est noté. J'ai spécifié que ce n'est pas une classe publique, et la méthode protégée getCallerClass () dans java.lang.System est présente sur toutes les machines virtuelles 1,5+ que j'ai examinées, y compris IBM, JRockit et Sun, mais votre affirmation est prudente. .
Nicholas

6
@Software Monkey, comme d'habitude, "tout dépend". Faire quelque chose comme ça pour aider au débogage ou tester la journalisation - surtout si cela ne se termine jamais dans le code de production - ou si la cible de déploiement est strictement le PC du développeur, sera probablement correct. Quiconque pense toujours le contraire, même dans de tels cas: il faudrait en fait expliquer le raisonnement « vraiment mauvaise idée» mieux que de simplement dire que c'est mauvais ...

8
En outre, selon une logique similaire, vous pouvez également affirmer que chaque fois que vous utilisez une fonctionnalité spécifique à Hibernate qui n'est pas compatible JPA, c'est toujours une " très mauvaise idée". Ou si vous allez utiliser des fonctionnalités spécifiques à Oracle qui ne sont pas disponibles dans d'autres bases de données, c'est une " très mauvaise idée". Bien sûr, c'est un état d'esprit plus sûr et certainement de bons conseils pour certaines utilisations, mais jetant automatiquement des outils utiles simplement parce que cela ne fonctionnera pas avec une configuration logicielle que vous n'utilisez pas du tout ? C'est un peu trop rigide et un peu idiot.

5
L'utilisation non surveillée de classes spécifiques au fournisseur présentera une probabilité plus élevée de problèmes, mais il convient de déterminer un chemin pour se dégrader gracieusement si la classe en question n'est pas présente (ou est interdite pour une raison quelconque). Une politique de refus catégorique d'utiliser des classes spécifiques à un fournisseur est, à mon avis, un peu naïve. Parcourez le code source de certaines des bibliothèques que vous utilisez en production et voyez si l'une d'entre elles le fait. (sun.misc.Unsafe peut-être?)
Nicholas

7
     /**
       * Get the method name for a depth in call stack. <br />
       * Utility function
       * @param depth depth in the call stack (0 means current method, 1 means call method, ...)
       * @return method name
       */
      public static String getMethodName(final int depth)
      {
        final StackTraceElement[] ste = new Throwable().getStackTrace();

        //System. out.println(ste[ste.length-depth].getClassName()+"#"+ste[ste.length-depth].getMethodName());
        return ste[ste.length - depth].getMethodName();
      }

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)

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils". <br />
          * From the Stack Trace.
          * @return "[class#method(line)]: " (never empty, first class past StackTraceUtils)
          */
        public static String getClassMethodLine()
        {
            return getClassMethodLine(null);
        }

        /**
          * Returns the first "[class#method(line)]: " of the first class not equal to "StackTraceUtils" and aclass. <br />
          * Allows to get past a certain class.
          * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
          * @return "[class#method(line)]: " (never empty, because if aclass is not found, returns first class past StackTraceUtils)
          */
        public static String getClassMethodLine(final Class aclass)
        {
            final StackTraceElement st = getCallingStackTraceElement(aclass);
            final String amsg = "[" + st.getClassName() + "#" + st.getMethodName() + "(" + st.getLineNumber()
            +")] <" + Thread.currentThread().getName() + ">: ";
            return amsg;
        }

     /**
       * Returns the first stack trace element of the first class not equal to "StackTraceUtils" or "LogUtils" and aClass. <br />
       * Stored in array of the callstack. <br />
       * Allows to get past a certain class.
       * @param aclass class to get pass in the stack trace. If null, only try to get past StackTraceUtils. 
       * @return stackTraceElement (never null, because if aClass is not found, returns first class past StackTraceUtils)
       * @throws AssertionFailedException if resulting statckTrace is null (RuntimeException)
       */
      public static StackTraceElement getCallingStackTraceElement(final Class aclass)
      {
        final Throwable           t         = new Throwable();
        final StackTraceElement[] ste       = t.getStackTrace();
        int index = 1;
        final int limit = ste.length;
        StackTraceElement   st        = ste[index];
        String              className = st.getClassName();
        boolean aclassfound = false;
        if(aclass == null)
        {
            aclassfound = true;
        }
        StackTraceElement   resst = null;
        while(index < limit)
        {
            if(shouldExamine(className, aclass) == true)
            {
                if(resst == null)
                {
                    resst = st;
                }
                if(aclassfound == true)
                {
                    final StackTraceElement ast = onClassfound(aclass, className, st);
                    if(ast != null)
                    {
                        resst = ast;
                        break;
                    }
                }
                else
                {
                    if(aclass != null && aclass.getName().equals(className) == true)
                    {
                        aclassfound = true;
                    }
                }
            }
            index = index + 1;
            st        = ste[index];
            className = st.getClassName();
        }
        if(resst == null) 
        {
            //Assert.isNotNull(resst, "stack trace should null"); //NO OTHERWISE circular dependencies 
            throw new AssertionFailedException(StackTraceUtils.getClassMethodLine() + " null argument:" + "stack trace should null"); //$NON-NLS-1$
        }
        return resst;
      }

      static private boolean shouldExamine(String className, Class aclass)
      {
          final boolean res = StackTraceUtils.class.getName().equals(className) == false && (className.endsWith("LogUtils"
            ) == false || (aclass !=null && aclass.getName().endsWith("LogUtils")));
          return res;
      }

      static private StackTraceElement onClassfound(Class aclass, String className, StackTraceElement st)
      {
          StackTraceElement   resst = null;
          if(aclass != null && aclass.getName().equals(className) == false)
          {
              resst = st;
          }
          if(aclass == null)
          {
              resst = st;
          }
          return resst;
      }

J'avais besoin de quelque chose qui fonctionne avec Java 1.4 et cette réponse a été très utile! Je vous remercie!
RGO

6

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.


Cool; tu n'as pas à le jeter?
krosenvold

Non, au moins c'est comme ça que je m'en souviens, je ne l'ai pas fait depuis quelques années, mais je suis à peu près sûr que la nouvelle exception ne fait que créer un objet, et lever l'exception ne fait rien d'autre que passer à la clause catch ().
Bill K

Soigné. J'étais enclin à le lancer pour simuler une exception réelle.
Sathish

Non, depuis Java 5, il existe une méthode sur Thread pour obtenir la pile actuelle sous la forme d'un tableau de StackTraceElements; ce n'est toujours pas bon marché, mais moins cher que l'ancienne solution d'analyse des exceptions.
Lawrence Dol

@Software Monkey Bien que je sois sûr que c'est plus approprié, qu'est-ce qui vous fait dire que c'est moins cher? Je suppose que le même mécanisme serait utilisé, et sinon, pourquoi en ralentir un quand il fait la même chose?
Bill K

1
private void parseExceptionContents(
      final Exception exception,
      final OutputStream out)
   {
      final StackTraceElement[] stackTrace = exception.getStackTrace();
      int index = 0;
      for (StackTraceElement element : stackTrace)
      {
         final String exceptionMsg =
              "Exception thrown from " + element.getMethodName()
            + " in class " + element.getClassName() + " [on line number "
            + element.getLineNumber() + " of file " + element.getFileName() + "]";
         try
         {
            out.write((headerLine + newLine).getBytes());
            out.write((headerTitlePortion + index++ + newLine).getBytes() );
            out.write((headerLine + newLine).getBytes());
            out.write((exceptionMsg + newLine + newLine).getBytes());
            out.write(
               ("Exception.toString: " + element.toString() + newLine).getBytes());
         }
         catch (IOException ioEx)
         {
            System.err.println(
                 "IOException encountered while trying to write "
               + "StackTraceElement data to provided OutputStream.\n"
               + ioEx.getMessage() );
         }
      }
   }

0

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:

public class InstanceCount{
    private static Map<Integer, CounterInstanceLog> instanceMap = new HashMap<Integer, CounterInstanceLog>();
private CounterInstanceLog counterInstanceLog;


    public void count() {
        counterInstanceLog= new counterInstanceLog();
    if(counterInstanceLog.getIdHashCode() != 0){
    try {
        if (instanceMap .containsKey(counterInstanceLog.getIdHashCode())) {
         counterInstanceLog= instanceMap .get(counterInstanceLog.getIdHashCode());
    }

    counterInstanceLog.incrementCounter();

            instanceMap .put(counterInstanceLog.getIdHashCode(), counterInstanceLog);
    }

    (...)
}

Et l'objet:

public class CounterInstanceLog{
    private int idHashCode;
    private StackTraceElement[] arrayStackTraceElements;
    private int instanceCount;
    private String callerClassName;

    private StackTraceElement getProjectClasses(int depth) {
      if(depth< 10){
        getCallerClassName(sun.reflect.Reflection.getCallerClass(depth).getName());
        if(getCallerClassName().startsWith("com.yourproject.model")){
            setStackTraceElements(Thread.currentThread().getStackTrace());
            setIdHashCode();
        return arrayStackTraceElements[depth];
        }
        //+2 because one new item are added to the stackflow
        return getProjectClasses(profundidade+2);           
      }else{
        return null;
      }
    }

    private void setIdHashCode() {
        if(getNomeClasse() != null){
            this.idHashCode = (getCallerClassName()).hashCode();
        }
    }

    public void incrementaContador() {
    this.instanceCount++;
}

    //getters and setters

    (...)



}

0
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter;

class DBConnection {
    String createdBy = null;

    DBConnection(Throwable whoCreatedMe) {
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        PrintWriter pw = new PrintWriter(os);
        whoCreatedMe.printStackTrace(pw);
        try {
            createdBy = os.toString();
            pw.close();
            os.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

public class ThrowableTest {

    public static void main(String[] args) {

        Throwable createdBy = new Throwable(
                "Connection created from DBConnectionManager");
        DBConnection conn = new DBConnection(createdBy);
        System.out.println(conn.createdBy);
    }
}

OU

public static interface ICallback<T> { T doOperation(); }


public class TestCallerOfMethod {

    public static <T> T callTwo(final ICallback<T> c){
        // Pass the object created at callee to the caller
        // From the passed object we can get; what is the callee name like below.
        System.out.println(c.getClass().getEnclosingMethod().getName());
        return c.doOperation();
    }

    public static boolean callOne(){
        ICallback callBackInstance = new ICallback(Boolean){
            @Override
            public Boolean doOperation() 
            {
                return true;
            }
        };
        return callTwo(callBackInstance);
    }

    public static void main(String[] args) {
         callOne();
    }
}

0

utilisez cette méthode: -

 StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
 stackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
 System.out.println(e.getMethodName());

L'appelant de l'exemple de méthode Code est ici: -

public class TestString {

    public static void main(String[] args) {
        TestString testString = new TestString();
        testString.doit1();
        testString.doit2();
        testString.doit3();
        testString.doit4();
    }

    public void doit() {
        StackTraceElement[] stacktrace = Thread.currentThread().getStackTrace();
        StackTraceElement e = stacktrace[2];//maybe this number needs to be corrected
        System.out.println(e.getMethodName());
    }

    public void doit1() {
        doit();
    }

    public void doit2() {
        doit();
    }

    public void doit3() {
        doit();
    }

    public void doit4() {
        doit();
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.