【问题标题】:Java or any other language: Which method/class invoked mine?Java 或任何其他语言:哪个方法/类调用了我的?
【发布时间】:2011-03-28 22:35:23
【问题描述】:

我想在我的方法内部编写一个代码,打印出哪个方法/类调用了它。

(我的假设是除了我的方法我什么都不能改变......)

其他编程语言怎么样?

编辑:谢谢大家,JavaScript 怎么样? Python? C++?

【问题讨论】:

  • 我一再被一些人“想写的”奇怪的黑客行为所震惊。没有冒犯的意思。
  • @del 这并不是真正的黑客攻击。它基本上是一种非常有用的日志记录形式。
  • 哎呀,忽略我的“可能重复”。没有注意到其他语言。 :)
  • 某种需要特定于语言,除非询问提供这种设施的主观理念。

标签: java javascript python programming-languages classloader


【解决方案1】:

在 Python 中,您使用 inspect 模块。 获取函数的名称和文件名很容易,如下例所示。

获取函数本身需要更多的工作。我想你可以使用__import__ 函数来导入调用者的模块。但是,您必须以某种方式将文件名转换为有效的模块名称。

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

【讨论】:

    【解决方案2】:

    在 Python 中,您应该使用 traceback 或 inspect 模块。这些 will 模块将使您免受解释器的实现细节的影响,即使在今天也可能有所不同(例如 IronPython、Jython),并且将来可能会发生更多变化。然而,这些模块在今天的标准 Python 解释器下执行此操作的方式是使用 sys._getframe()。特别是 sys._getframe(1).f_code.co_name 提供了您想要的信息。

    【讨论】:

      【解决方案3】:

      贾斯汀的一般情况下;我想提一下这段代码展示的两个特殊情况:

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

      打印出来:

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

      尽管第一个是从main()“直接”调用的,第二个是从SomeInnerClass.someInnerMethod() 调用的。这是两种方法之间进行透明调用的两种情况。

      • 在第一种情况下,这是因为我们将bridge method 调用为泛型方法,由编译器添加以确保 SomeReifiedGeneric 可以用作原始类型。
      • 在第二种情况下,这是因为我们从内部类调用 WhoCalledMe 的私有成员。为此,编译器添加了一种合成方法作为中间人来解决可见性问题。

      【讨论】:

        【解决方案4】:

        由于您询问了其他语言,Tcl 为您提供了一个命令 (info level),可让您检查调用堆栈。例如,[info level -1] 返回当前过程的调用者,以及用于调用当前过程的参数。

        【讨论】:

          【解决方案5】:

          这是 Java 特有的。

          您可以使用Thread.currentThread().getStackTrace()。这将返回一个 StackTraceElements 数组。

          数组中的第二个元素将是调用方法。

          例子:

          public void methodThatPrintsCaller() {
              StackTraceElement elem = Thread.currentThread.getStackTrace()[2];
              System.out.println(elem);
          
              // rest of you code
          }
          

          【讨论】:

          • 有几个特殊情况不适合发表评论,我将它们放在自己的答案中。
          • 那么 Java 数组现在是从 1 开始的吗? ;)
          • @strob,没有。你会打电话给arr[2] 或第二件事。 (从技术上讲,这是第 3 件事)(但是,那你怎么称呼第 0 件事呢?)
          【解决方案6】:

          是的,有可能。

          看看Thread.getStackTrace()

          【讨论】:

            【解决方案7】:

            如果您只想打印出堆栈跟踪并寻找类,请使用

            Thread.dumpStack();
            

            请参阅API doc

            【讨论】:

              【解决方案8】:

              方法调用的序列位于堆栈中。这是获取堆栈的方式:Get current stack trace in Java 然后获取上一项。

              【讨论】:

              • 呵呵,链接到我的答案!谢谢。
              猜你喜欢
              • 2015-02-25
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-11-19
              • 2010-09-20
              • 2019-07-23
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多