有些时候,我们需要知道方法是从哪里调用到自己这里的,本文就是探讨如何获取这个栈。
Java是通过StackTrace
类来存储堆栈的轨迹信息的。获取当前方法的调用栈可以通过Thread.currentThread().getStackTrace()
,他就会返回一个StackTraceElement[]
数组,然后我们就可以通过StackTraceElement
来获取调用所在的类,调用的方法名称来得到整个调用栈的信息。他的顺序是从自己开始知道调用线程的发起点。例如我们要打印调用所在类与调用的方法名称:
1 | StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); |
StackTraceElement
他表示StackTrace
堆栈中的一个元素,我们可以通过他得知一些方法的调用信息,常用的方法如下:
getClassName()
调用方法所在类,如果是内部类,则是会带有$
符号的全类名称getMethodName()
调用方法的名称getLineNumber()
获取调用行,是该方法在类中的行数,即该方法在那个行(以类计算)中调用了下一个方法getFileName()
在那个文件中被调用的toString()
该方法StackTraceElement自身有重写,他会返回,他的实现如下,我们经常在异常上看到的Unknown Source
就是该方法的返回原因。1
2
3
4
5
6
7public String toString() {
return getClassName() + "." + methodName +
(isNativeMethod() ? "(Native Method)" :
(fileName != null && lineNumber >= 0 ?
"(" + fileName + ":" + lineNumber + ")" :
(fileName != null ? "("+fileName+")" : "(Unknown Source)")));
}
获取调用栈的方式
除了上面我们说的Thread.currentThread().getStackTrace()
,我们还可以声明一个异常,然后不抛出也可以,比如(new Exception()).getStackTrace()
,前者也是这样获得的。
我们假如需要获取当前应用所有线程的调用栈,则可以使用Thread.getAllStackTraces()
,他返回一个Map<Thread, StackTraceElement[]>
对象。
异常的堆栈
我们获取堆栈都是通过Throwable
本身或者他的子类来获取的,然后我们日常中也经常看到e.printStackTrace()
方法,那我们就来具体了解下该类的异常相关的方法。
首先,我们看下它提供的一些对外可调用的关于异常的方法
printStackTrace()
和printStackTrace(PrintStream s)
方法,前者是调用后者的,我们直接看后者即可,他是把当前的堆栈信息打印到输入流s
中,比如常见的System.err
或者System.out
等printStackTrace(PrintWriter s)
,该方法是把PrintWriter
包装成了一个getMessage()
&getLocalizedMessage()
, 返回简单的错误信息,不包含堆栈信息,后返回的是对象的locale-specific
描述,如果子类没有重写则返回与前者一样的数据。子类可以重写这两个方法返回不同的信息。getStackTrace()
获取StackTraceElement[]
,可以通过它得到调用栈fillInStackTrace()
,它会清空当前的栈的trace信息,然后再当前位置重新建立栈的trace信息。我们假如自定义的时候,不关心stack trace的话则可以直接重写该方法,然后返回this
即可,会对性能有优化作用。