2010-08-12 20 views
11

Me gustaría escribir un código interno para mi método que imprime qué método/clase lo ha invocado.Java o cualquier otro idioma: ¿Qué método/clase invocó el mío?

(Mi suposición es que no puedo cambiar nada, pero mi método ..)

¿Qué hay de otros lenguajes de programación?

EDITAR: Gracias chicos, ¿qué tal JavaScript? ¿pitón? C++?

+2

Me sorprenden repetidamente los hacks raros que algunas personas "quisieran escribir". Sin ofender. – delnan

+3

@del Esto no es realmente un truco. Básicamente es una forma de registro que puede ser realmente útil. – jjnguy

+1

geeking out .. :-) – DuduAlul

Respuesta

18

Esto es específico para Java.

Puede usar Thread.currentThread().getStackTrace(). Esto devolverá una matriz de StackTraceElements.

El segundo elemento de la matriz será el método de llamada.

Ejemplo:

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

    // rest of you code 
} 
+0

Hay un par de casos especiales para esto que no fueron adecuados para un comentario, los puse en su propia respuesta. –

+0

¿Entonces las matrices de Java están basadas en 1 ahora? ;) – Stroboskop

+1

@strob, no. Llamarás a 'arr [2]' o a la 2da cosa. (Técnicamente es la tercera cosa) (Pero, ¿cómo se llama la cosa?) – jjnguy

2

la secuencia de llamadas a métodos se encuentra en la pila. así es como obtienes la pila: Get current stack trace in Java y luego obtienes el artículo anterior.

+1

Hehe, ¡eso se vincula a una respuesta mía! Gracias. – jjnguy

4

Si todo lo que quieres hacer es imprimir el seguimiento de pila e ir a la caza de la clase, utilizar

Thread.dumpStack(); 

Véase el API doc.

1

ya que preguntas acerca de otros idiomas, Tcl le da una orden (info level) que le permite examinar la pila de llamadas. Por ejemplo, [info level -1] devuelve la persona que llama del procedimiento actual, así como los argumentos utilizados para llamar al procedimiento actual.

4

Justin tiene el caso general abajo; Quería mencionar dos casos especiales demostradas por esta 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; 
    } 
} 

Esta impresora:

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

pesar de que el primero se llama "directamente" de main() y el segundo de SomeInnerClass.someInnerMethod(). Estos son dos casos donde hay una llamada transparente hecha entre los dos métodos.

  • En el primer caso, esto se debe a que estamos llamando la bridge method a un método genérico, añadido por el compilador para asegurar SomeReifiedGeneric se puede utilizar como un tipo de prima.
  • En el segundo caso, es porque estamos llamando a un miembro privado de WhoCalledMe de una clase interna. Para lograr esto, el compilador agrega un método sintético como intermediario para anular los problemas de visibilidad.
+2

Esos son algunos puntos buenos. – jjnguy

0

En Python, debe utilizar el rastreo o inspeccionar los módulos. Estos módulos le protegerán de los detalles de implementación del intérprete, que pueden diferir incluso hoy (por ejemplo, IronPython, Jython) y pueden cambiar aún más en el futuro.La forma en que estos módulos lo hacen bajo el intérprete estándar de Python hoy, sin embargo, es con sys._getframe(). En particular, sys._getframe (1) .f_code.co_name proporciona la información que desea.

1

En Python utiliza el módulo inspect. Obtener el nombre de la función y el nombre del archivo es fácil, como puede ver en el siguiente ejemplo.

Obtener la función en sí es más trabajo. Creo que podría usar la función __import__ para importar el módulo de la persona que llama. Sin embargo, de alguna manera debe convertir el nombre de archivo a un nombre de módulo válido.

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() 
Cuestiones relacionadas