这是代码:
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
我检查它调用的Thread.currentThread().getStackTrace()
(new Exception()).getStackTrace();
。在这种情况下,为什么我会得到不同的结果?
提前致谢!
答案 0 :(得分:1)
要了解发生了什么,请首先逐项打印整个堆栈跟踪。以下是您要获得的内容(demo):
-- 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)
请注意,唯一的区别在于两个堆栈跟踪的初始项:第二个在顶部包含一个额外的框架。
填充Throwable
堆栈的方法似乎用Throwable
或其子类的构造函数排除了框架,以及在构建它的过程中调用的其他方法。
这是有道理的,因为当您看到异常的堆栈跟踪时,您希望在顶部看到throw方法,并忽略创建异常需要您调用其构造函数的事实。
另一方面,线程的getStackTrace()
方法不会将自己从堆栈中移除。这就是你打印出来时在堆栈顶部看到的内容。
答案 1 :(得分:1)
由于您已经正确地注意到自己,Thread.currentThread().getStackTrace()
调用了(new Exception()).getStackTrace();
这意味着前者的堆栈跟踪只会延长一帧。
如果一个方法调用另一个方法,则根据定义,它们的堆栈跟踪不能相同。