最近學習的JVM小冊中老師提了個問題:
最開始我覺得是1,結果程序跑出來是0,感到很疑惑,於是查看了下字節碼:
從字節碼可以看出:
0:定義變量0
1:將0存入本地變量表slot-0
2:加載slot-0到操作數棧
3:將棧頂元素存入本地變量表slot-1
4:對slot-0自增
7-8:加載slot-1到操作數棧並返回
可以看到,最終返回的是slot-1的值,而自增的是slot-0的值,所以最終還是返回的0
但是爲什麼JVM要這麼做的原因的還是不太清楚,看了Java虛擬機規範上面寫的:
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.2.5
規範這裏也說的是如果try裏面有return,那麼編譯的時候會先把try的返回值存入到本地變量表中。看到這裏我有了一些猜測:
try-finally的原理是編譯的時候在return之前插入了jsr指令,執行該指令會跳到finally block,finally block這個時候被編譯成了一個subroutine(子程序),
也就是一個方法,那麼爲了當從subroutine跳轉出來的時候能夠繼續返回原來要返回的值,所以在執行finally block之前會先把try的返回值存入本地變量表中一個新的slot,而在finally
當中如果有操作try的返回值這個變量的時候,實際操作的是該值原本所在的slot,,說的有點繞,不太好理解,望見諒。
老師在羣裏發了個javac編譯的代碼,這個比較清楚:
所以大致可以總結爲:當try有return的時候,finally裏面對try的返回值的操作不起作用。我們也可以將程序改一下:
當try裏面沒有return的時候,則返回1。在看看此時的字節碼:
這個時候,就沒有將return的值暫存的操作了。