从堆栈跟踪元素中获取实际 class

Get actual class from stack trace element

我可以使用 Eclipse 设置断点并在调试视图中查看当前堆栈跟踪:

但是当我使用 Thread.currentThread().getStackTrace() 检查堆栈跟踪时,我得到的信息并不完全相同。例如,所选元素是 JUnitTestClassReference,堆栈跟踪中的相关元素(破折号内)是 JUnit4TestReference(它的超类,可能是因为 run 方法未被子类覆盖)。

org.springframework.test.context.junit4.SpringJUnit4ClassRunner
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
org.junit.runners.ParentRunner
org.junit.runners.ParentRunner
org.junit.runners.ParentRunner
org.junit.runners.ParentRunner
org.junit.runners.ParentRunner
org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks
org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks
org.junit.runners.ParentRunner
org.springframework.test.context.junit4.SpringJUnit4ClassRunner
---- org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference ----
org.eclipse.jdt.internal.junit.runner.TestExecution
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner

StackTraceElement 不包含对所涉及的实际对象的引用,仅包含对 class 的引用。我可以想到为什么这实际上是一个好主意的许多原因,尤其是 StackTraceElement.

的所有可序列化性

StackTraceElement 中的 class 引用被定义为引用 class 声明 方法,而不是 class发生异常时持有该方法的当前对象。这可能是为了区分超级实现和覆盖实现。因此,只有 post-exception 堆栈跟踪,实际对象和实际子 class 都无法(再)获得。

Eclipse(和其他调试器界面)向您显示程序的实时跟踪 运行。您正确地注意到此实时信息是通过 JPDA 获得的。

Java 调试接口 (JDI) 可以访问表示为 StackFrame 的实时堆栈帧信息,其中实际对象可用:

ObjectReference thisObject()

Returns the value of 'this' for the current frame. The ObjectReference for 'this' is only available for non-native instance methods.

堆栈记录 code 正在等待调用 return,而不是 objects。如果该方法在superclass中,而subclass没有覆盖它,堆栈将记录superclass方法,因为那是控制最终必须的地方return到.

在运行时 class 获取所涉及对象的唯一方法是检查激活帧中针对特定方法调用的 this 引用的值。调试器可以告诉你,但是没有真正简单的方法从 Java 本身得到它,你必须使用像 JDI 这样的调试接口。

请注意还有另一个挑战:StackTraceElement 报告了一个 class name,而不是 class object。由于 ClassLoader 的工作方式,同一 VM 中可能有两个同名的 class,而 StackTraceElement 无法提供足够的信息来区分它们. (这就是像 Tomcat 这样的容器可以为同一 VM 中的两个不同应用程序加载同一库的两个不同版本的方式。)

也许这有助于将来参考,因为我遇到了同样的问题,并且想知道如何做到这一点

您可以使用 StackTraceElementStackTraceElement 获取方法对象:

//replace with your StackTraceElement 
StackTraceElement method_obj = Thread.currentThread().getStackTrace()[0]

Class<?> object_context = Class.forName(method_obj.className)
Method method = object_context.getMethod(method_obj.methodName, null)