Come posso trovare il chiamante di un metodo usando stacktrace o reflection?


392

Devo trovare il chiamante di un metodo. È possibile utilizzare stacktrace o reflection?


5
Mi chiedo solo, ma perché dovresti farlo?
Juliet,

2
Ho una classe Parent (modello MVC) con un evento di notifica e solo i setter delle mie sottoclassi chiamano questo metodo. non voglio sporcare il mio codice con un argomento ridondante. Preferirei che il metodo nella classe genitore capisse il setter che lo chiamava.
Sathish,

30
@Sathish Sembra che dovresti ripensare quel design
krosenvold,

7
@Juliet Come parte del refactoring di un grosso blocco di codice, recentemente ho cambiato un metodo che viene utilizzato da molte cose. C'è un certo modo per rilevare se il codice stava usando correttamente il nuovo metodo, quindi stavo stampando la classe e il numero di riga che lo chiamava in quei casi. Al di fuori della registrazione, non vedo alcun reale scopo per qualcosa del genere. Anche se in un certo senso voglio scrivere API ora che generano un DontNameYourMethodFooExceptionse il metodo di chiamata si chiama foo.
Cruncher,

5
Trovo che essere in grado di ottenere il chiamante del mio metodo uno strumento di debug inestimabile: ecco come una ricerca web mi ha portato qui. Se il mio metodo viene chiamato da più posizioni, viene chiamato dalla posizione corretta al momento giusto? Al di fuori del debug o della registrazione, l'utilità è probabilmente limitata nella migliore delle ipotesi, come menziona @Cruncher.
Ogre Salmo33,

Risposte:


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

Secondo i Javadocs:

L'ultimo elemento dell'array rappresenta il fondo dello stack, che è l'invocazione del metodo meno recente nella sequenza.

Una StackTraceElementha getClassName(), getFileName(), getLineNumber()e getMethodName().

Dovrai sperimentare per determinare quale indice vuoi (probabilmente stackTraceElements[1]o [2]).


7
Dovrei notare che getStackTrace () crea ancora un'eccezione, quindi non è molto più veloce, solo più conveniente.
Michael Myers

42
Nota che questo metodo non ti darà il chiamante, ma solo il tipo di chiamante . Non avrai un riferimento all'oggetto che chiama il tuo metodo.
Joachim Sauer,

3
Solo una nota a margine, ma su un thread.currentThread 1.5 (JVM) di JVM (). GetStackTrace () sembra essere molto più lento della creazione di una nuova eccezione () (circa 3 volte più lenta). Ma come già notato, non dovresti comunque usare codice come questo in un'area critica per le prestazioni. ;) Una JVM 1.6 sembra essere solo ~ 10% più lenta e, come diceva Software Monkey, esprime l'intento meglio del modo "nuova eccezione".
GaZ

21
@Eelco Thread.currentThread () è economico. Thread.getStackTrace () è costoso perché, a differenza di Throwable.fillInStackTrace (), non vi è alcuna garanzia che il metodo venga chiamato dallo stesso thread che sta esaminando, quindi la JVM deve creare un "safepoint" - bloccare l'heap e lo stack. Vedi questo bug report: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
David Moles

7
@JoachimSauer conosci un modo per ottenere un riferimento all'oggetto che chiama il metodo?
jophde,

216

Una soluzione alternativa può essere trovata in un commento a questa richiesta di miglioramento . Utilizza il getClassContext()metodo di un'abitudine SecurityManagere sembra essere più veloce del metodo di traccia stack.

Il seguente programma verifica la velocità dei diversi metodi suggeriti (il bit più interessante è nella classe interna 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 esempio dell'output del mio MacBook Intel Core 2 Duo a 2,4 GHz con Java 1.6.0_17:

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

Il metodo Reflection interno è molto più veloce degli altri. Ottenere una traccia dello stack da una nuova creazione Throwableè più veloce che ottenerla dalla corrente Thread. E tra i modi non interni di trovare la classe chiamante l'abitudine SecurityManagersembra essere la più veloce.

Aggiornare

Come sottolineato da Lyomi in questo commento, il sun.reflect.Reflection.getCallerClass()metodo è stato disabilitato per impostazione predefinita nell'aggiornamento 40 di Java 7 e rimosso completamente in Java 8. Ulteriori informazioni al riguardo in questo problema nel database dei bug Java .

Aggiornamento 2

Come ha scoperto zammbi , Oracle è stata costretta a ritirarsi dalla modifica che ha rimosso il file sun.reflect.Reflection.getCallerClass(). È ancora disponibile in Java 8 (ma è obsoleto).

Aggiornamento 3

3 anni dopo: aggiornamento dei tempi con l'attuale JVM.

> 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
Sì, sembra così. Ma nota che i tempi che do nell'esempio sono per un milione di chiamate, quindi a seconda di come lo stai usando potrebbe non essere un problema.
Johan Kaving,

1
La rimozione della riflessione dal mio progetto ha comportato un aumento della velocità di 10 volte.
Kevin Parker,

1
Sì, la riflessione in generale è lenta (vedi ad esempio stackoverflow.com/questions/435553/java-reflection-performance ), ma in questo caso specifico l'utilizzo della classe sun.reflect.Reflection interna è la più veloce.
Johan Kaving,

1
In realtà non è necessario. Puoi verificarlo modificando il codice sopra per stampare il className restituito (e suggerisco di ridurre il conteggio dei cicli a 1). Vedrai che tutti i metodi restituiscono lo stesso className - TestGetCallerClassName.
Johan Kaving,

1
getCallerClass è obsoleto e verrà rimosso in 7u40 .. triste :(
lyomi il

36

Sembra che tu stia cercando di evitare di passare un riferimento al thismetodo. Passare thisè molto meglio che trovare il chiamante attraverso la traccia dello stack corrente. Rifattorizzare con un design più OO è ancora meglio. Non dovresti aver bisogno di conoscere il chiamante. Passare un oggetto callback, se necessario.


6
++ Conoscere il chiamante è troppa informazione. Se è necessario, è possibile passare a un'interfaccia, ma ci sono buone probabilità che sia necessario un refactoring importante. @satish dovrebbe pubblicare il suo codice e divertirci un po ':)
Bill K,

15
Esistono validi motivi per voler farlo. Ho avuto alcune occasioni in cui l'ho trovato utile durante i test, ad esempio.
Eelco,

2
@chillenious Lo so :) L'ho fatto da solo per creare un metodo come quello in LoggerFactory.getLogger(MyClass.class)cui non dovevo passare letteralmente in classe. Raramente è ancora la cosa giusta da fare.
Craig P. Motlin,

6
Questo è un buon consiglio in generale, ma non risponde alla domanda.
Navin,

1
Un esempio concreto di quando potrebbe essere la decisione GIUSTA sulla progettazione di ottenere informazioni sul chiamante è quando si implementa l' INotifyPropertyChangedinterfaccia .NET . Mentre questo esempio specifico non è in Java, lo stesso problema può manifestarsi quando si tenta di modellare campi / getter come stringhe per Reflection.
Chris Kerekes,

31

Java 9 - JEP 259: API Stack-Walking

JEP 259 fornisce un'API standard efficiente per lo stack walking che consente un facile filtraggio e un accesso pigro alle informazioni nelle tracce dello stack. Prima dell'API Stack-Walking, i modi più comuni per accedere ai frame dello stack erano:

Throwable::getStackTracee Thread::getStackTracerestituisce una matrice di StackTraceElementoggetti, che contengono il nome della classe e il nome del metodo di ciascun elemento stack-trace.

SecurityManager::getClassContextè un metodo protetto, che consente a una SecurityManagersottoclasse di accedere al contesto della classe.

sun.reflect.Reflection::getCallerClassMetodo interno JDK che non dovresti usare comunque

L'uso di queste API è generalmente inefficiente:

Queste API richiedono alla VM di acquisire con entusiasmo un'istantanea dell'intero stack e restituiscono informazioni che rappresentano l'intero stack. Non è possibile evitare il costo dell'esame di tutti i frame se il chiamante è interessato solo ai primi frame dello stack.

Per trovare la classe del chiamante immediato, prima ottenere un StackWalker:

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

Quindi chiama il getCallerClass():

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

o walkthe se StackFrameottieni il primo precedente StackFrame:

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

15

Oneliner :

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

Si noti che potrebbe essere necessario sostituire 2 con 1.


10

Questo metodo fa la stessa cosa ma un po 'più semplicemente e forse un po' più performante e nel caso in cui stai usando la riflessione, salta automaticamente quei fotogrammi. L'unico problema è che potrebbe non essere presente nelle JVM non Sun, sebbene sia incluso nelle classi di runtime di JRockit 1.4 -> 1.6. (Il punto è che non è una classe pubblica ).

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

Per quanto riguarda il realFramesToSkipvalore, le versioni di Sun 1.5 e 1.6 VM di java.lang.System, esiste un metodo pacchetto protetto chiamato getCallerClass () che chiama sun.reflect.Reflection.getCallerClass(3), ma nella mia classe di utilità helper ho usato 4 poiché c'è il frame aggiunto della classe helper invocazione.


16
L'utilizzo di classi di implementazione JVM è davvero cattiva idea.
Lawrence Dol,

7
Notato. Ho specificato che non è una classe pubblica e che il metodo protetto getCallerClass () in java.lang.System è presente su tutte le VM 1.5+ che ho visto, inclusi IBM, JRockit e Sun, ma la tua affermazione è prudentemente valida .
Nicholas

6
@Software Monkey, come al solito, "dipende tutto". Fare qualcosa del genere per facilitare il debug o la registrazione dei test - specialmente se non finisce mai nel codice di produzione - o se la destinazione di distribuzione è strettamente il PC dello sviluppatore, probabilmente andrà bene. Chiunque pensi ancora diversamente anche in questi casi: dovresti spiegare il ragionamento dell '"idea davvero cattiva" meglio che dire semplicemente che è male ...

8
Inoltre, con la logica simile si potrebbe anche sostenere che ogni volta che si utilizza una funzionalità di sospensione specifico che non è compatibile con APP, che è sempre un " davvero pessima idea". Oppure, se avete intenzione di utilizzare le funzionalità di Oracle-specifici che non sono disponibili in altri database, si tratta di un " davvero pessima idea". Certo è una mentalità più sicura e sicuramente un buon consiglio per determinati usi, ma buttare via automaticamente strumenti utili solo perché non funzionerà con una configurazione software che tu non stai usando ? È un po 'troppo flessibile e un po' sciocco.

5
L'uso incustodito di classi specifiche del fornitore presenterà una maggiore probabilità di problemi, ma si dovrebbe determinare un percorso per degradare con grazia se la classe in questione non è presente (o è vietata per qualche motivo). A mio avviso, una politica di rifiuto totale di utilizzare qualsiasi classe specifica del venditore è un po 'ingenua. Cerca nel codice sorgente di alcune delle librerie che usi in produzione e vedi se qualcuno di loro lo fa. (sun.misc.Unsafe forse?)
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();
      }

Ad esempio, se si tenta di ottenere la riga del metodo di chiamata a scopo di debug, è necessario superare la classe Utility in cui si codificano quei metodi statici:
(vecchio codice java1.4, solo per illustrare un potenziale utilizzo 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;
      }

Avevo bisogno di qualcosa che funzioni con Java 1.4 e questa risposta è stata molto utile! Grazie!
RGO

6

L'ho già fatto prima. Puoi semplicemente creare una nuova eccezione e prendere la traccia dello stack su di essa senza lanciarla, quindi esaminare la traccia dello stack. Come dice l'altra risposta, però, è estremamente costoso - non farlo in un ciclo ristretto.

L'ho già fatto per un'utilità di registrazione su un'app in cui le prestazioni non contavano molto (le prestazioni raramente contano molto, in realtà - purché si visualizzi rapidamente il risultato in un'azione come un clic di un pulsante).

Prima che fosse possibile ottenere la traccia dello stack, le eccezioni avevano solo .printStackTrace (), quindi ho dovuto reindirizzare System.out su un flusso di mia creazione, quindi (new Exception ()). PrintStackTrace (); Reindirizzare System.out indietro e analizzare il flusso. Cose divertenti.


Freddo; non devi buttarlo?
krosenvold,

No, almeno è così che me lo ricordo, non lo faccio da un po 'di anni, ma sono abbastanza sicuro che il rinnovo di un'eccezione sia solo la creazione di un oggetto, e il lancio dell'eccezione non fa nulla se non passare alla clausola catch ().
Bill K,

Neat. Ero propenso a lanciarlo per simulare una vera eccezione.
Sathish,

No, poiché Java 5 esiste un metodo su Thread per ottenere lo stack corrente come una matrice di StackTraceElements; non è ancora economico, ma più economico della vecchia soluzione di analisi delle eccezioni.
Lawrence Dol,

@Software Monkey Anche se sono sicuro che sia più appropriato, cosa ti fa dire che è più economico? Suppongo che sarebbe usato lo stesso meccanismo e, in caso contrario, perché rallentare quando fa la stessa cosa?
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

Ecco una parte del codice che ho creato sulla base dei suggerimenti mostrati in questo argomento. Spero che sia d'aiuto.

(Sentiti libero di dare qualche suggerimento per migliorare questo codice, per favore dimmelo)

Il contatore:

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);
    }

    (...)
}

E l'oggetto:

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);
    }
}

O

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

utilizzare questo metodo: -

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

Il chiamante del metodo esempio è qui: -

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();
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.