2010-08-12 2 views
11

Vorrei scrivere un codice interno al mio metodo che stampa quale metodo/classe lo ha richiamato.Java o qualsiasi altra lingua: quale metodo/classe ha invocato il mio?

(La mia ipotesi è che non posso cambiare nulla, ma il mio metodo ..)

Come su altri linguaggi di programmazione?

MODIFICA: Grazie ragazzi, che ne dici di JavaScript? pitone? C++?

+2

Sono ripetutamente sbalordito da quello strano hacks che alcune persone "vorrebbero scrivere". Senza offesa significava. – delnan

+3

@del Questo non è davvero un hack. È fondamentalmente una forma di registrazione che può essere davvero utile. – jjnguy

+1

geeking out .. :-) – DuduAlul

risposta

18

Questo è specifico per Java.

È possibile utilizzare Thread.currentThread().getStackTrace(). Ciò restituirà una matrice di StackTraceElements.

Il secondo elemento dell'array sarà il metodo di chiamata.

Esempio:

public void methodThatPrintsCaller() { 
    StackTraceElement elem = Thread.currentThread.getStackTrace()[2]; 
    System.out.println(elem); 

    // rest of you code 
} 
+0

Ci sono un paio di casi speciali a questo che non erano adatti per un commento, li ho inseriti nella loro risposta. –

+0

Quindi gli array Java sono basati su 1 ora? ;) – Stroboskop

+1

@strob, no. Chiamerai 'arr [2]' o la seconda cosa. (Tecnicamente è la terza cosa) (Ma come si chiama la 0ª cosa?) – jjnguy

2

la sequenza di chiamate di metodo si trova nello stack. questo è il modo in cui ottieni lo stack: Get current stack trace in Java quindi ottieni l'elemento precedente.

+1

Hehe, che collega a una mia risposta! Grazie. – jjnguy

4

Se tutto quello che vogliamo fare è stampare la traccia dello stack e andare a caccia di classe, utilizzare

Thread.dumpStack(); 

Vedere le API doc.

1

Dal momento che hai chiesto di altre lingue, Tcl ti dà un comando (info level), che consente di esaminare lo stack di chiamate. Ad esempio, [info level -1] restituisce il chiamante della procedura corrente, nonché gli argomenti utilizzati per chiamare la procedura corrente.

4

Justin ha risolto il caso generale; Ho voluto citare due casi particolari dimostrate da questo snippit:

import java.util.Comparator; 

public class WhoCalledMe { 

    public static void main(String[] args) { 
     ((Comparator)(new SomeReifiedGeneric())).compare(null, null); 
     new WhoCalledMe().new SomeInnerClass().someInnerMethod(); 
    } 

    public static StackTraceElement getCaller() { 
     //since it's a library function we use 3 instead of 2 to ignore ourself 
     return Thread.currentThread().getStackTrace()[3]; 
    } 

    private void somePrivateMethod() { 
     System.out.println("somePrivateMethod() called by: " + WhoCalledMe.getCaller()); 
    } 

    private class SomeInnerClass { 
     public void someInnerMethod() { 
      somePrivateMethod(); 
     } 
    } 
} 

class SomeReifiedGeneric implements Comparator<SomeReifiedGeneric> { 
    public int compare(SomeReifiedGeneric o1, SomeReifiedGeneric o2) { 
     System.out.println("SomeRefiedGeneric.compare() called by: " + WhoCalledMe.getCaller()); 
     return 0; 
    } 
} 

Questo stampa:

SomeRefiedGeneric.compare() called by: SomeReifiedGeneric.compare(WhoCalledMe.java:1) 
somePrivateMethod() called by: WhoCalledMe.access$0(WhoCalledMe.java:14) 

Anche se il primo si chiama "direttamente" dal main() e il secondo da SomeInnerClass.someInnerMethod(). Questi sono due casi in cui è presente una chiamata trasparente tra i due metodi.

  • Nel primo caso, questo è perché che chiamiamo bridge method ad un metodo generico, aggiunto dal compilatore per garantire SomeReifiedGeneric può essere utilizzato come un tipo grezzo.
  • Nel secondo caso, è perché stiamo chiamando un membro privato di WhoCalledMe da una classe interna. Per fare ciò, il compilatore aggiunge un metodo sintetico come intermediario per ignorare i problemi di visibilità.
+2

Questi sono alcuni buoni punti. – jjnguy

0

In Python, è necessario utilizzare il traceback o ispezionare i moduli. Questi moduli ti proteggeranno dai dettagli dell'implementazione dell'interprete, che possono differire anche oggi (ad esempio IronPython, Jython) e potrebbero cambiare ancora di più in futuro.Il modo in cui questi moduli fanno oggi l'interprete standard di Python, tuttavia, è con sys._getframe(). In particolare, sys._getframe (1) .f_code.co_name fornisce le informazioni desiderate.

1

In Python si utilizza il modulo inspect. Ottenere il nome della funzione e il nome del file è facile, come si vede nell'esempio seguente.

Ottenere la funzione stessa è più lavoro. Penso che potresti usare la funzione __import__ per importare il modulo del chiamante. Tuttavia, in qualche modo devi convertire il nome del file in un nome di modulo valido.

import inspect 

def find_caller(): 
    caller_frame = inspect.currentframe().f_back 
    print "Called by function:", caller_frame.f_code.co_name 
    print "In file   :", caller_frame.f_code.co_filename 
    #Alternative, probably more portable way 
    #print inspect.getframeinfo(caller_frame) 

def foo(): 
    find_caller() 

foo()