Wie werden Argumente an die Methode übergeben, die diese Methode aufgerufen hat?

Lesezeit: 5 Minuten

Benutzer-Avatar
Tom

In Java ist es möglich, die Klasse und Methode abzurufen, die die aktuelle Methode aufgerufen haben (die Methode, in der Sie den StackTrace erhalten).

Kann ich die Argumente abrufen, die an die Methode übergeben wurden, die diese Methode aufgerufen hat?

Ich brauche dies für Debugging-Zwecke.

Z.B:

baseClass {
   initialFunc(input) {
       var modifiedInput = input + " I modified you";
       otherClass.doSomething(modifiedInput);
   }
}

otherClass {
    doSomething(input)  {
         //GET THE ARGUMENTS PASSED TO THE METHOD OF THE CLASS THAT CALLED THIS METHOD
    }
}

Kann man diese Informationen aus dem Stacktrace bekommen, oder gibt es andere Mittel?

(Beachten Sie, dass ich dies zur Laufzeit tun muss und die Quelle von baseClass nicht wirklich ändern kann. Dies wird eine Funktion meiner Debugging-Klasse sein, die die Quelle vorher nicht kennt.)

  • Sie können, wenn Sie einen Debugger anhängen, sonst – nein. Die Parameter befinden sich möglicherweise in CPU-Registern (nicht auf dem Stack).

    – bestes

    9. Februar 2011 um 10:38 Uhr


  • Ich fürchte, ich kann für meine Zwecke keinen Debugger anhängen

    – Tom

    9. Februar 2011 um 10:39 Uhr

  • Dann sind Sie verloren, abgesehen von ClassLoader und der Erweiterung der Klasse im laufenden Betrieb, um die Argumente abzufangen. (aber du würdest nicht fragen, ob du wüsstest wie)

    – bestes

    9. Februar 2011 um 10:42 Uhr


  • Wenn ein Debugger das kann, dann muss es irgendwie möglich sein. AFAIK, ein Debugger verwendet keine Code-Instrumentierung oder ähnliches, da er an jeden Java-Prozess angehängt werden kann. Keine Ahnung, wie das funktioniert, vielleicht etwas JMX?

    – maaartinus

    9. Februar 2011 um 10:54 Uhr

  • @bestsss, das führte mich zu einer Folgefrage: stackoverflow.com/questions/4945358/… – Ich habe diese Frage akzeptiert.

    – Tom

    9. Februar 2011 um 13:17 Uhr

Ich glaube nicht, dass dies mit der Standard-Java-API möglich ist.

Was Sie tun könnten, ist, AspectJ zu verwenden, einen Point-Cut an der aufrufenden Methode zu platzieren, die Argumente zu speichern, einen Point-Cut an der aufgerufenen Methode zu platzieren und die Argumente weiterzugeben.

Eine andere (etwas fortgeschrittenere) Option besteht darin, einen benutzerdefinierten, den Bytecode umschreibenden Klassenlader zu verwenden, der die ursprünglichen Argumente speichert und sie als zusätzliche Argumente an die nächste Methode weiterleitet. Dies würde wahrscheinlich ein oder zwei Tage dauern, um es umzusetzen. Geeignete Frameworks sind BCEL oder ASM.

  • Der AspectJ-Ansatz würde mich dazu zwingen, die Quelle vor der Laufzeit zu ändern, daher ist dies keine Option. Kann ich bei der anderen Option eine JRE-Erweiterung erstellen, die jede Klasse aktualisiert, die jede Methode verwendet? Wenn ja, welche Klasse verwenden Methoden/Funktionen in der JRE?

    – Tom

    9. Februar 2011 um 10:43 Uhr

  • Hier ist ein AspectJ-Beispiel in einer ähnlichen Frage: stackoverflow.com/a/14089562/603516

    – Wadzim

    13. Juni 2019 um 17:45 Uhr

Benutzer-Avatar
Christoph Klewes

Ich denke, das könnte möglich sein, weil input liegt außerhalb des Gültigkeitsbereichs, ist aber noch nicht für die Garbage Collection zugänglich, daher ist der Wert noch vorhanden, aber leider glaube ich nicht, dass es eine Standard-API-Methode gibt, um darauf zuzugreifen. Dies könnte möglicherweise mit einem benutzerdefinierten implementierten NDC möglich sein (verschachtelter diagnostischer Kontext) für den Logging-Ansatz.

  • Formale Parameter werden als lokale Variablen betrachtet, deren Inhalt auf dem Stack gespeichert und daher niemals müllgesammelt werden.

    – aiobe

    9. Februar 2011 um 10:37 Uhr

  • es ist überhaupt nicht notwendig, auf dem Stack gespeichert zu werden. Die Methode kann inline sein und/oder die Parameter können sich in CPU-Registern befinden (was mit dem „heißen“ Code passiert)

    – bestes

    9. Februar 2011 um 10:40 Uhr


  • Sind Sie sicher, dass es keine Möglichkeit gibt, darauf zuzugreifen?

    – Tom

    9. Februar 2011 um 10:40 Uhr

  • @Tom, wenn Sie einen anderen Agenten mit Debug-Einstellungen ausführen, können Sie das tun. Normalerweise kannst du das nicht.

    – bestes

    9. Februar 2011 um 10:41 Uhr

  • @bestsss, ich spreche vom Stack der Aktivierungsdatensätze des jvm.

    – aiobe

    9. Februar 2011 um 10:43 Uhr

Ich bin mir nicht sicher, warum Sie dies jemals in Java tun möchten?

Die einzige Möglichkeit, die mir einfällt, besteht darin, ein benutzerdefiniertes Wrapper-Objekt für die übergebene Zeichenfolge zu erstellen und so die Referenz jedes Mal anstelle einer neuen Zeichenfolge an den Wrapper zu senden.
Ich würde jedoch davon abraten, da es Ihren ursprünglichen Code unübersichtlich macht und ihn noch fehleranfälliger macht.

Könnte dieses Problem nicht mit einem Debugger, wie dem in Eclipse integrierten, gelöst werden, um Ihren Zustand zu überprüfen?

In meinem Fall musste ich einen Parameterwert abrufen, der an eine Methode in einem bestimmten Stapelrahmen übergeben wurde, um später im Ausführungsablauf verwendet zu werden

ich benutzte ThreadLocal um es zu speichern, und wenn ich es brauchte, konnte ich es an jedem Punkt im Code abrufen, wie ich es deklariert hatte public static

Hier ist ein Skelettbeispiel

public static final ThreadLocal<SomeType> IMPORTANT_THREAD_LOCAL_FOR_BLA = ThreadLocal.withInitial(whatever);

methodWithImportantParam(SomeType importantValue){
    // save it in the static threadLocal Field
    this.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()=importantValue;// code to set the value
    // continue method logic
}

und irgendwo im Code, wo Sie diesen Wert benötigen

YourClass.IMPORTANT_THREAD_LOCAL_FOR_BLA.get()

Stellen Sie jedoch sicher, dass der Ausführungsfluss den Wert festlegt, und rufen Sie ihn dann ab

Ich hoffe, meine Antwort fügt dieser Frage etwas Wertvolles hinzu

Sie können den Namen der aufrufenden Methode und ihrer Klasse abrufen, aber Sie müssen der aktuellen Methode etwas Code hinzufügen:

    public static void main(String[] args) throws Exception {
    call();
}

private static void call() {
    Exception exception = new Exception();
    for(StackTraceElement trace : exception.getStackTrace()){
        System.out.println(trace.getMethodName());
    }
}

Dadurch werden “call” und “main”, Methodennamen in aufgerufener Reihenfolge (umgekehrt) ausgegeben.

Benutzer-Avatar
Kev

Dies ist mit der Reflection-API möglich!

public class StackTrace {
    public static void main(String args[]) {
        StackTrace st = new StackTrace();
        st.func();
    }
    public void func() {
        OtherClass os =new OtherClass();
        os.getStackTrace(this);
    }
}

class OtherClass {
    void getStackTrace(Object obj)  {
        System.out.println(obj.getClass());
    }
}

1016820cookie-checkWie werden Argumente an die Methode übergeben, die diese Methode aufgerufen hat?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy