Java或其他语言:哪个方法/类调用了我的方法?

13

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

(我的假设是除了我的方法,我不能改变任何东西...)

其他编程语言呢?

编辑:谢谢大家,JavaScript? python? C++呢?


2
我经常对一些人想要编写的奇怪黑科技感到惊讶。并无冒犯之意。 - user395760
3
这不是真正的“黑客攻击”,它基本上是一种记录形式,可以非常有帮助。 - jjnguy
1
糟糕,不要理会我的“可能重复”。没有注意到其他的语言。 :) - Adam Paynter
@adam 你可以通过点赞轻松补偿;-) 哈哈 - DuduAlul
1
需要根据语言具体情况而定,除非在询问提供此类功能的主观哲学。 - Tom Hawtin - tackline
8个回答

20

这是针对Java的特定方法。

你可以使用Thread.currentThread().getStackTrace(),这将返回一个包含StackTraceElements的数组。

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

例如:

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

    // rest of you code
}

有几个特殊情况不适合作为评论,我将它们放在了自己的答案中。 - Mark Peters
Java 数组现在是从1开始的了? ;) - Stroboskop
1
@strob,不可以。你应该叫做arr[2] 或者第二个元素。(技术上来讲它是第三个元素)(但是,那么第零个元素该怎么叫呢?) - jjnguy

4
如果你只想打印出堆栈跟踪并查找类,可以使用以下方法:
Thread.dumpStack();

See the API doc.


4

Justin已经掌握了一般情况;我想提到这个片段演示的两个特殊情况:

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()调用的。这两种情况都存在在两个方法之间进行透明调用的情况。
  • 在第一种情况下,这是因为我们正在调用桥接方法来调用通用方法,由编译器添加以确保SomeReifiedGeneric可以用作原始类型。
  • 在第二种情况下,这是因为我们正在从内部类中调用WhoCalledMe的私有成员。为了实现这一点,编译器会添加一个合成方法作为过渡来解决可见性问题。

3

1
哈哈,那链接指向我的一个答案!谢谢。 - jjnguy

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

1

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


0

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接