为什么使用java.lang.Throwable#getStackTrace和java.lang.Thread#getStackTrace会得到不同的StackTrace

为什么使用java.lang.Throwable#getStackTrace和java.lang.Thread#getStackTrace会得到不同的StackTrace,java,jvm,Java,Jvm,以下是代码: package stacktrace.test; public class A { public static void main(String[] args) { B.f(); } } interface B { static void f() { C.f(); } } interface C { static void f() { StackTraceElement[] stackTr

以下是代码:

package stacktrace.test;

public class A {
    public static void main(String[] args) {
        B.f();
    }
}

interface B {
    static void f() {
        C.f();
    }
}

interface C {
    static void f() {
        StackTraceElement[] stackTrace1 = (new Exception()).getStackTrace();
        StackTraceElement[] stackTrace2 = Thread.currentThread().getStackTrace();
        StackTraceElement x1 = stackTrace1[1];
        StackTraceElement x2 = stackTrace2[1];
        System.out.println(x1.getClassName());
        System.out.println(x2.getClassName());
    }
}
和输出:

stacktrace.test.B
stacktrace.test.C
我检查它调用的
(新异常()).getStackTrace()的
线程.currentThread().getStackTrace()
。在这种情况下,为什么我会得到不同的结果


提前谢谢

要了解发生了什么,请从逐项打印整个堆栈跟踪开始。下面是您将得到的():

请注意,唯一的区别在于两个堆栈跟踪的初始项:第二个堆栈跟踪在顶部包含一个额外的帧

填充
可丢弃
堆栈的方法似乎排除了具有
可丢弃
或其子类的构造函数的框架,以及在构建它的过程中调用的其他方法

这是有意义的,因为当您看到异常的堆栈跟踪时,您希望看到顶部的抛出方法,而忽略创建异常需要调用其构造函数这一事实


另一方面,线程的
getStackTrace()
方法不会将自身从堆栈中移除。这就是打印时在堆栈顶部看到的内容。

正如您自己正确注意到的,
Thread.currentThread().getStackTrace()
调用
(新异常()).getStackTrace()
这意味着前者的stacktrace正好长一帧


如果一个方法调用另一个方法,它们的堆栈跟踪在定义上不能相同。

它有什么不同?调用堆栈是不同的,但在这两种情况下,您都在访问第二个堆栈跟踪元素。@apangin,omg!。你说得对。很明显!我同意你的建议是有道理的,但这只是一个建议。如果能从文档中得到一些官方证据就好了。@slesh这两种方法的文档是相同的。区别在于本机代码实现了
fillStackTrace
方法的
Throwable
-- stackTrace1
C.f(Main.java:23)
B.f(Main.java:17)
A.main(Main.java:11)

-- stackTrace2
java.lang.Thread.getStackTrace(Thread.java:1556)
C.f(Main.java:24)
B.f(Main.java:17)
A.main(Main.java:11)