Wie finde ich den Aufrufer einer Methode mithilfe von Stacktrace oder Reflection?


392

Ich muss den Aufrufer einer Methode finden. Ist es möglich, Stacktrace oder Reflection zu verwenden?


5
Ich frage mich nur, aber warum sollten Sie das tun müssen?
Julia

2
Ich habe eine übergeordnete Klasse (MVC-Modell) mit einem Notifier-Ereignis und nur Setter meiner Unterklassen rufen diese Methode auf. Ich möchte meinen Code nicht mit einem redundanten Argument verunreinigen. Ich möchte lieber, dass die Methode in der übergeordneten Klasse den Setter herausfindet, der sie aufgerufen hat.
Sathish

30
@Sathish Klingt so, als ob Sie dieses Design
überdenken

7
@Juliet Im Rahmen der Umgestaltung eines großen Codefutters habe ich kürzlich eine Methode geändert, die von vielen Dingen verwendet wird. Es gibt eine bestimmte Methode, um festzustellen, ob der Code die neue Methode ordnungsgemäß verwendet hat. Daher habe ich die Klassen- und Zeilennummer gedruckt, die sie in diesen Fällen aufgerufen hat. Außerhalb der Protokollierung sehe ich keinen wirklichen Zweck für so etwas. Obwohl ich jetzt irgendwie APIs schreiben möchte, die ein werfen, DontNameYourMethodFooExceptionwenn die aufrufende Methode foo heißt.
Cruncher

5
Ich finde es ein unschätzbares Debugging-Tool, den Aufrufer meiner Methode zu bekommen: So hat mich eine Websuche hierher gebracht. Wenn meine Methode von mehreren Orten aus aufgerufen wird, wird sie zur richtigen Zeit vom richtigen Ort aus aufgerufen? Außerhalb des Debuggens oder Protokollierens ist der Nutzen wahrscheinlich bestenfalls begrenzt, wie @Cruncher erwähnt.
Oger Psalm33

Antworten:


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

Nach Angaben der Javadocs:

Das letzte Element des Arrays stellt den unteren Rand des Stapels dar. Dies ist der am wenigsten aktuelle Methodenaufruf in der Sequenz.

A StackTraceElementhat getClassName(), getFileName(), getLineNumber()und getMethodName().

Sie müssen experimentieren, um festzustellen, welchen Index Sie möchten (wahrscheinlich stackTraceElements[1]oder [2]).


7
Ich sollte beachten, dass getStackTrace () immer noch eine Ausnahme erstellt, sodass dies nicht wirklich schneller ist - nur bequemer.
Michael Myers

42
Beachten Sie, dass diese Methode nicht den Anrufer, sondern nur den Typ des Anrufers angibt . Sie haben keinen Verweis auf das Objekt, das Ihre Methode aufruft.
Joachim Sauer

3
Nur eine Randnotiz, aber auf einem 1,5 JVM Thread.currentThread (). GetStackTrace () scheint viel langsamer zu sein als das Erstellen einer neuen Exception () (ungefähr dreimal langsamer). Wie bereits erwähnt, sollten Sie Code wie diesen ohnehin nicht in einem leistungskritischen Bereich verwenden. ;) Eine 1.6 JVM scheint nur ~ 10% langsamer zu sein und drückt, wie Software Monkey sagte, die Absicht besser aus als die "neue Ausnahme".
GaZ

21
@Eelco Thread.currentThread () ist billig. Thread.getStackTrace () ist teuer, da im Gegensatz zu Throwable.fillInStackTrace () keine Garantie dafür besteht, dass die Methode von demselben Thread aufgerufen wird, den sie untersucht. Daher muss die JVM einen "Sicherheitspunkt" erstellen, der den Heap und den Stapel sperrt. Siehe diesen Fehlerbericht: bugs.sun.com/bugdatabase/view_bug.do?bug_id=6375302
David Moles

7
@JoachimSauer Kennen Sie eine Möglichkeit, einen Verweis auf das Objekt zu erhalten, das die Methode aufruft?
Jophde

216

Eine alternative Lösung finden Sie in einem Kommentar zu dieser Verbesserungsanforderung . Es verwendet die getClassContext()Methode eines benutzerdefinierten SecurityManagerund scheint schneller als die Stack-Trace-Methode zu sein.

Das folgende Programm testet die Geschwindigkeit der verschiedenen vorgeschlagenen Methoden (das interessanteste Bit ist in der inneren Klasse 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.");
  }
}

Ein Beispiel für die Ausgabe meines Intel Core 2 Duo MacBook mit 2,4 GHz und Java 1.6.0_17:

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

Die interne Reflexionsmethode ist viel schneller als die anderen. Das Abrufen eines Stack-Trace von einem neu erstellten Throwableist schneller als das Abrufen vom aktuellen Thread. Und unter den nicht internen Methoden zum Auffinden der Anruferklasse SecurityManagerscheint der Brauch der schnellste zu sein.

Aktualisieren

Wie lyomi in diesem Kommentar hervorhebt , wurde die sun.reflect.Reflection.getCallerClass()Methode in Java 7 Update 40 standardmäßig deaktiviert und in Java 8 vollständig entfernt. Weitere Informationen hierzu finden Sie in dieser Ausgabe in der Java-Fehlerdatenbank .

Update 2

Wie zammbi herausgefunden hat, war Oracle gezwungen, sich von der Änderung zurückzuziehen, durch die das entfernt wurde sun.reflect.Reflection.getCallerClass(). Es ist weiterhin in Java 8 verfügbar (aber veraltet).

Update 3

3 Jahre danach: Update zum Timing mit der aktuellen 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
Ja, so scheint es. Beachten Sie jedoch, dass die im Beispiel angegebenen Zeiten für eine Million Anrufe gelten. Je nachdem, wie Sie dies verwenden, ist dies möglicherweise kein Problem.
Johan Kaving

1
Für mich führte das Entfernen der Reflexion aus meinem Projekt zu einer 10-fachen Geschwindigkeitssteigerung.
Kevin Parker

1
Ja, die Reflexion ist im Allgemeinen langsam (siehe z. B. stackoverflow.com/questions/435553/java-reflection-performance ), aber in diesem speziellen Fall ist die Verwendung der internen sun.reflect.Reflection-Klasse die schnellste.
Johan Kaving

1
Das muss es eigentlich nicht. Sie können dies überprüfen, indem Sie den obigen Code ändern, um den zurückgegebenen Klassennamen zu drucken (und ich schlage vor, die Anzahl der Schleifen auf 1 zu reduzieren). Sie werden sehen, dass alle Methoden denselben Klassennamen zurückgeben - TestGetCallerClassName.
Johan Kaving

1
getCallerClass ist veraltet und wird in 7u40 entfernt .. sad :(
lyomi

36

Klingt so, als würden Sie vermeiden, einen Verweis auf thisdie Methode zu übergeben. Das Übergeben thisist viel besser als das Auffinden des Anrufers über die aktuelle Stapelverfolgung. Das Refactoring zu einem OO-Design ist noch besser. Sie sollten den Anrufer nicht kennen müssen. Übergeben Sie gegebenenfalls ein Rückrufobjekt.


6
++ Den Anrufer zu kennen, ist zu viel Information. Wenn Sie müssen, können Sie eine Schnittstelle übergeben, aber es besteht eine gute Chance, dass ein umfangreiches Refactoring erforderlich ist. @ Satish sollte seinen Code posten und uns etwas Spaß damit haben lassen :)
Bill K

15
Es gibt gültige Gründe dafür. Ich hatte einige Gelegenheiten, in denen ich es zum Beispiel beim Testen hilfreich fand.
Eelco

2
@chillenious Ich weiß :) Ich habe es selbst gemacht, um eine Methode zu erstellen, LoggerFactory.getLogger(MyClass.class)bei der ich das Klassenliteral nicht weitergeben musste. Es ist immer noch selten das Richtige.
Craig P. Motlin

6
Dies ist im Allgemeinen ein guter Rat, der jedoch die Frage nicht beantwortet.
Navin

1
Ein konkretes Beispiel dafür, wann es die RICHTIGE Entwurfsentscheidung sein könnte, Informationen über den Aufrufer abzurufen, ist die Implementierung der .NET- INotifyPropertyChangedSchnittstelle. Obwohl dieses spezielle Beispiel nicht in Java enthalten ist, kann sich das gleiche Problem manifestieren, wenn versucht wird, Felder / Getter als Zeichenfolgen für Reflection zu modellieren.
Chris Kerekes

31

Java 9 - JEP 259: Stack-Walking-API

JEP 259 bietet eine effiziente Standard-API für das Stack-Walking, mit der die Informationen in Stack-Traces einfach gefiltert und verzögert abgerufen werden können. Vor der Stack-Walking-API wurden häufig auf Stack-Frames zugegriffen:

Throwable::getStackTraceund Thread::getStackTraceein Array von StackTraceElementObjekten zurückgeben, die den Klassennamen und den Methodennamen jedes Stack-Trace-Elements enthalten.

SecurityManager::getClassContextist eine geschützte Methode, mit der eine SecurityManagerUnterklasse auf den Klassenkontext zugreifen kann.

JDK-interne sun.reflect.Reflection::getCallerClassMethode, die Sie sowieso nicht verwenden sollten

Die Verwendung dieser APIs ist normalerweise ineffizient:

Diese APIs erfordern, dass die VM eifrig einen Snapshot des gesamten Stapels erfasst , und sie geben Informationen zurück, die den gesamten Stapel darstellen. Es gibt keine Möglichkeit, die Kosten für die Prüfung aller Frames zu vermeiden, wenn der Aufrufer nur an den obersten Frames auf dem Stapel interessiert ist.

Um die Klasse des unmittelbaren Anrufers zu finden, erhalten Sie zunächst Folgendes StackWalker:

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

Dann rufen Sie entweder an getCallerClass():

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

oder walkdas StackFrames und bekomme das erste vorhergehende StackFrame:

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

15

Oneliner :

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

Beachten Sie, dass Sie möglicherweise die 2 durch 1 ersetzen müssen.


10

Diese Methode macht dasselbe, aber etwas einfacher und möglicherweise etwas performanter. Wenn Sie Reflektion verwenden, werden diese Frames automatisch übersprungen. Das einzige Problem ist, dass es möglicherweise nicht in Nicht-Sun-JVMs vorhanden ist, obwohl es in den Laufzeitklassen von JRockit 1.4 -> 1.6 enthalten ist. (Punkt ist, es ist keine öffentliche Klasse).

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

Was den realFramesToSkipWert der Sun java.lang.System1.5- und 1.6-VM-Versionen angeht, gibt es eine paketgeschützte Methode namens getCallerClass (), die aufgerufen wird. sun.reflect.Reflection.getCallerClass(3)In meiner Hilfsprogrammklasse habe ich jedoch 4 verwendet, da der Hilfsrahmen der Hilfsklasse hinzugefügt wurde Aufruf.


16
Die Verwendung von JVM-Implementierungsklassen ist eine wirklich schlechte Idee.
Lawrence Dol

7
Notiert. Ich habe angegeben, dass es sich nicht um eine öffentliche Klasse handelt, und die geschützte Methode getCallerClass () in java.lang.System ist auf allen über 1,5 VMs vorhanden, die ich mir angesehen habe, einschließlich IBM, JRockit und Sun, aber Ihre Behauptung ist konservativ fundiert .
Nicholas

6
@ Software Monkey, wie immer, "es kommt alles darauf an". Wenn Sie so etwas tun, um das Debuggen oder Testen der Protokollierung zu unterstützen - insbesondere, wenn es nie im Produktionscode landet - oder wenn das Bereitstellungsziel ausschließlich der PC des Entwicklers ist, ist dies wahrscheinlich in Ordnung. Jeder, der auch in solchen Fällen noch anders denkt: Sie müssten die Argumentation " wirklich schlechte Idee" besser erklären, als nur zu sagen, dass sie schlecht ist ...

8
Mit einer ähnlichen Logik könnten Sie auch argumentieren, dass es immer eine " wirklich schlechte Idee" ist, wenn Sie eine Hibernate-spezifische Funktion verwenden, die nicht JPA-kompatibel ist . Oder wenn Sie Oracle-spezifische Funktionen verwenden, die in anderen Datenbanken nicht verfügbar sind, ist dies eine " wirklich schlechte Idee". Sicher ist es eine sicherere Einstellung und auf jeden Fall ein guter Rat für bestimmte Verwendungszwecke, aber automatisch Wegwerfen nützliche Werkzeuge , nur weil es mit einer Software - Konfiguration wird nicht funktionieren , dass Sie, äh .. nicht zu verwenden ? Das ist ein bisschen zu unflexibel und ein bisschen albern.

5
Die unbewachte Verwendung herstellerspezifischer Klassen führt zu einer höheren Wahrscheinlichkeit von Problemen. Es sollte jedoch ein Pfad festgelegt werden, der sich ordnungsgemäß verschlechtert, wenn die betreffende Klasse nicht vorhanden ist (oder aus irgendeinem Grund verboten ist). Eine Politik der pauschalen Weigerung, herstellerspezifische Klassen zu verwenden, ist meiner Meinung nach ein wenig naiv. Stöbern Sie im Quellcode einiger der Bibliotheken, die Sie in der Produktion verwenden, und prüfen Sie, ob eine von ihnen dies tut. (sun.misc.Unsafe vielleicht?)
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();
      }

Wenn Sie beispielsweise versuchen, die aufrufende Methodenzeile für
Debugzwecke abzurufen , müssen Sie die Utility-Klasse überschreiten, in der Sie diese statischen Methoden codieren : (alter Java1.4-Code, nur um eine mögliche Verwendung von StackTraceElement zu veranschaulichen)

        /**
          * 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;
      }

Ich brauchte etwas, das mit Java 1.4 funktioniert und diese Antwort war sehr hilfreich! Vielen Dank!
RGO

6

Ich habe das schon mal gemacht. Sie können einfach eine neue Ausnahme erstellen und die Stapelverfolgung darauf abrufen, ohne sie zu werfen, und dann die Stapelverfolgung untersuchen. Wie die andere Antwort jedoch sagt, ist es extrem kostspielig - tun Sie es nicht in einer engen Schleife.

Ich habe es bereits für ein Protokollierungsdienstprogramm in einer App getan, bei der die Leistung keine große Rolle spielte (Leistung spielt eigentlich selten eine große Rolle - solange Sie das Ergebnis einer Aktion wie einem schnellen Klicken auf eine Schaltfläche anzeigen).

Bevor Sie den Stack-Trace abrufen konnten, hatten Ausnahmen nur .printStackTrace (), sodass ich System.out in einen Stream meiner eigenen Erstellung umleiten musste, dann (new Exception ()). PrintStackTrace (); Leiten Sie System.out zurück und analysieren Sie den Stream. Lustige Sachen.


Cool; du musst es nicht werfen?
Krosenvold

Nein, zumindest erinnere ich mich so daran, ich habe es seit einigen Jahren nicht mehr getan, aber ich bin mir ziemlich sicher, dass das Neueinstellen einer Ausnahme nur das Erstellen eines Objekts ist und das Auslösen der Ausnahme nichts anderes bewirkt, als zu bestehen es zur catch () -Klausel.
Bill K

Ordentlich. Ich war geneigt, es zu werfen, um eine tatsächliche Ausnahme zu simulieren.
Sathish

Nein, seit Java 5 gibt es eine Methode für Thread, um den aktuellen Stapel als Array von StackTraceElements abzurufen. Es ist immer noch nicht billig, aber billiger als die alte Lösung zum Parsen von Ausnahmen.
Lawrence Dol

@ Software Monkey Obwohl ich sicher bin, dass es angemessener ist, warum sagst du dann, dass es billiger ist? Ich würde annehmen, dass derselbe Mechanismus verwendet wird, und wenn nicht, warum sollte man einen langsamer machen, wenn er dasselbe tut?
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

Hier ist ein Teil des Codes, den ich basierend auf den in diesem Thema gezeigten Hinweisen erstellt habe. Ich hoffe es hilft.

(Fühlen Sie sich frei, Vorschläge zur Verbesserung dieses Codes zu machen, bitte sagen Sie mir)

Der Zähler:

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

    (...)
}

Und das Objekt:

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

ODER

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

Verwenden Sie diese Methode: -

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

Beispiel für einen Aufruf des Methodencodes Code ist hier: -

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();
    }
}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.