在Java8中获取调用方方法的有效方法?

在Java8中获取调用方方法的有效方法?,java,performance,exception,stack-frame,throwable,Java,Performance,Exception,Stack Frame,Throwable,这就是我想要实现的:如果有一个方法a()调用方法b(),我想知道是谁调用了方法b() public void a(){ b();//但它不一定在同一个类中 } 公共空间b(){ String方法=getCallerMethod();//返回“a” } 现在,使用StackWalkerAPI,可以在Java9+中高效地实现这一点。在Java8中,我可以使用Thread.currentThread().getStackTrace()或newException().getStackTrace(),但

这就是我想要实现的:如果有一个方法
a()
调用方法
b()
,我想知道是谁调用了方法
b()

public void a(){
b();//但它不一定在同一个类中
}
公共空间b(){
String方法=getCallerMethod();//返回“a”
}
现在,使用
StackWalker
API,可以在Java9+中高效地实现这一点。在Java8中,我可以使用
Thread.currentThread().getStackTrace()
newException().getStackTrace()
,但这两种方法都非常慢。我不需要整个stacktrace,我只需要stacktrace中的前一帧,并且只需要该帧中的方法名(可能还有类名)


在Java 8中有没有有效的方法来实现这一点?

您可以创建am异常并使用
fillInStacktrace()
,然后
printStacktrace()
并粘贴结果

它的效率可能不太高,但如果只是为了调试,我不明白为什么需要这样做

(我不在电脑前,所以我没有试着编译它):


您可以创建am异常并使用
fillInStacktrace()
,然后
printStacktrace()
并粘贴结果

它的效率可能不太高,但如果只是为了调试,我不明白为什么需要这样做

(我不在电脑前,所以我没有试着编译它):

  • 在JDK 8中,有一个内部未记录的API,它提供对单个堆栈跟踪元素的访问,而无需解码整个堆栈跟踪:

    SharedSecrets.getJavaLangAccess().getStackTraceDepth(e)
    SharedSecrets.getJavaLangAccess().getStackTraceElement(e, index)
    
    它有助于避免解码堆栈跟踪的巨大成本,但仍然需要收集整个跟踪。有关详细信息,请参阅

  • 更快的方法是JVMTI函数。其
    start\u depth
    max\u frame\u count
    参数只允许获取堆栈跟踪的选定部分

    这种方法的缺点是它需要一个本机库

    我有一种使用
    GetStackTrace
    的方法,它几乎可以满足您的需要:
    StackFrame.getLocation(depth)
    方法只返回给定深度的一个堆栈帧

  • 在只需要调用方类的情况下(没有确切的方法),可以使用快速、标准和可移植的解决方案

    MethodHandles.lookup().lookupClass()
    
  • 最后,如果您只需要调用方方法,另一种解决方案是查找调用方法
    a
    的所有
    invoke*
    字节码,并将它们重写为使用调用方调用方法
    a\u(String callerMethod)
    ,其中
    callerMethod
    参数是一个检测时间常数,从正在检测的方法派生

  • 在JDK 8中,有一个内部未记录的API,它提供对单个堆栈跟踪元素的访问,而无需解码整个堆栈跟踪:

    SharedSecrets.getJavaLangAccess().getStackTraceDepth(e)
    SharedSecrets.getJavaLangAccess().getStackTraceElement(e, index)
    
    它有助于避免解码堆栈跟踪的巨大成本,但仍然需要收集整个跟踪。有关详细信息,请参阅

  • 更快的方法是JVMTI函数。其
    start\u depth
    max\u frame\u count
    参数只允许获取堆栈跟踪的选定部分

    这种方法的缺点是它需要一个本机库

    我有一种使用
    GetStackTrace
    的方法,它几乎可以满足您的需要:
    StackFrame.getLocation(depth)
    方法只返回给定深度的一个堆栈帧

  • 在只需要调用方类的情况下(没有确切的方法),可以使用快速、标准和可移植的解决方案

    MethodHandles.lookup().lookupClass()
    
  • 最后,如果您只需要调用方方法,另一种解决方案是查找调用方法
    a
    的所有
    invoke*
    字节码,并将它们重写为使用调用方调用方法
    a\u(String callerMethod)
    ,其中
    callerMethod
    参数是一个检测时间常数,从正在检测的方法派生


  • 除非这是测试/调试代码,否则其行为取决于调用它的人的函数是一个糟糕的设计。@user13784117,实际上,这是为了调试目的。tl;dr:不,没有有效的方法来实现这一点,因为JVM的许多优化都依赖于在代码流中可以忽略方法边界这一事实。显式检查调用者会破坏这些优化,并强制JVM执行去优化代码(或者在这种情况下显式优化的代码,如果它足够聪明的话)。请看@apangin,是的,我在提出问题之前已经看到了这一点,看起来非常好,并对其进行了测试,在我的例子中,它将时间减少了5倍,这很好,但我仍然希望进一步减少时间(如果可能的话),除非这是测试/调试代码,一个行为取决于调用它的人的函数是一个糟糕的设计。@user13784117,实际上,这是为了调试目的。tl;dr:不,没有有效的方法来实现这一点,因为JVM的许多优化都依赖于在代码流中可以忽略方法边界这一事实。显式检查调用者会破坏这些优化,并强制JVM执行去优化代码(或者在这种情况下显式优化的代码,如果它足够聪明的话)。请看@apangin,是的,我在提出问题之前已经看到了这一点,看起来非常好,并对其进行了测试,在我的例子中,它将时间减少了5倍,这很好,但我仍然想进一步减少它(如果可能的话),你能提供一个例子吗please@Nfff3当然,你能举个例子吗please@Nfff3当然可以,他补充道。谢谢,我会坚持解决方案4,还有更多的工作要做,但这是最有效的。谢谢,我将坚持解决方案4,还有更多的工作要做,但它是最有效的。