緣起:
今天看到有一個工具類中有一句:
String msgToPrint = Thread.currentThread().getStackTrace()[1].getMethodName();
輸出的結果很簡單,就是調用類的方法名。
文檔:
public StackTraceElement[] getStackTrace()
-
返回一個表示該線程堆棧轉儲的堆棧跟蹤元素數組。如果該線程尚未啟動或已經終止,則該方法將返回一個零長度數組。如果返回的數組不是零長度的,則其第一個元素代表堆棧頂,它是該序列中最新的方法調用。最后一個元素代表堆棧底,是該序列中最舊的方法調用。
如果有安全管理器,並且該線程不是當前線程,則通過 RuntimePermission("getStackTrace") 權限調用安全管理器的 checkPermission 方法,查看是否可以獲取堆棧跟蹤。
某些虛擬機在某些情況下可能會從堆棧跟蹤中省略一個或多個堆棧幀。在極端情況下,沒有該線程堆棧跟蹤信息的虛擬機可以從該方法返回一個零長度數組。
- 返回:
- StackTraceElement 數組,每個數組代表一個堆棧幀。
其中使用的Thread類的第一個方法:
public static Thread currentThread()
第二個方法:(閱讀Java SE的文檔:)
public StackTraceElement[] getStackTrace()
返回一個堆棧軌跡元素的數組,代表了這個線程的堆棧情況。
如果:1.這個線程沒有被開啟;2.這個線程被開啟了但是沒有被系統運行過(因為線程運行是需要根據一定規律輪換的);3.這個線程結束了。
這三種情況下getStackTrace()返回的數組長度為0。
如果返回的數組長度不為0,那么數組的第一個元素代表棧頂元素,即是這個調用序列中最recent的方法。
數組的最后一個元素代表棧底元素,即調用序列中最遠的一個元素。
程序實測——Java程序
測試類,main方法如下:
public static void main(String[] args) { StackTraceElement[] stackTraceElements=Thread.currentThread().getStackTrace(); System.out.println("The stackTraceElements length:"+stackTraceElements.length); for(int i=0;i<stackTraceElements.length;i++){ System.out.println("\n---the "+i+" element"+"---"); System.out.println("toString:"+stackTraceElements[i].toString()); System.out.println("ClassName:"+stackTraceElements[i].getClassName()); System.out.println("FileName:"+stackTraceElements[i].getFileName()); System.out.println("LineNumber:"+stackTraceElements[i].getLineNumber()); System.out.println("MethodName:"+stackTraceElements[i].getMethodName()); } }
執行后輸出:
The stackTraceElements length:2 ---the 0 element--- toString:java.lang.Thread.getStackTrace(Thread.java:1567) ClassName:java.lang.Thread FileName:Thread.java LineNumber:1567 MethodName:getStackTrace ---the 1 element--- toString:Exchange.main(Exchange.java:10) ClassName:Exchange FileName:Exchange.java LineNumber:10 MethodName:main
如果再用一個私有方法,輸出調用堆棧的信息
public static void main(String[] args) { StackTraceElement[] stackTraceElements=Thread.currentThread().getStackTrace(); System.out.println("The stackTraceElements length:"+stackTraceElements.length); for(int i=0;i<stackTraceElements.length;i++){ System.out.println("\n---the "+i+" element"+"---"); System.out.println("toString:"+stackTraceElements[i].toString()); System.out.println("ClassName:"+stackTraceElements[i].getClassName()); System.out.println("FileName:"+stackTraceElements[i].getFileName()); System.out.println("LineNumber:"+stackTraceElements[i].getLineNumber()); System.out.println("MethodName:"+stackTraceElements[i].getMethodName()); } printStackInfos(); } private static void printStackInfos(){ StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace(); System.out.println("\nCalled in printStackInfos() method!!!"); System.out.println("The stackTraceElements length:"+stackTraceElements.length); for(int i =0;i<stackTraceElements.length;i++){ System.out.println("\n---the "+i+" element"+"---"); System.out.println("toString:"+stackTraceElements[i].toString()); System.out.println("ClassName:"+stackTraceElements[i].getClassName()); System.out.println("FileName:"+stackTraceElements[i].getFileName()); System.out.println("LineNumber:"+stackTraceElements[i].getLineNumber()); System.out.println("MethodName:"+stackTraceElements[i].getMethodName()); } }
則輸出結果如下:
The stackTraceElements length:2 ---the 0 element--- toString:java.lang.Thread.getStackTrace(Thread.java:1567) ClassName:java.lang.Thread FileName:Thread.java LineNumber:1567 MethodName:getStackTrace ---the 1 element--- toString:Exchange.main(Exchange.java:10) ClassName:Exchange FileName:Exchange.java LineNumber:10 MethodName:main Called in printStackInfos() method!!! The stackTraceElements length:3 ---the 0 element--- toString:java.lang.Thread.getStackTrace(Thread.java:1567) ClassName:java.lang.Thread FileName:Thread.java LineNumber:1567 MethodName:getStackTrace ---the 1 element--- toString:Exchange.printStackInfos(Exchange.java:24) ClassName:Exchange FileName:Exchange.java LineNumber:24 MethodName:printStackInfos ---the 2 element--- toString:Exchange.main(Exchange.java:20) ClassName:Exchange FileName:Exchange.java LineNumber:20 MethodName:main
可以看到加了一個私有方法之后,返回的堆棧元素就多了一個,並且它的位置在調用它的方法和被它調用的方法之間。