例如剛才的高階函數的例子:
我們來看下編譯後的 class 文件:
從編譯文件看到,剛才的高階函數調用處被編譯成了 Function0 的類型,因為我們的高階函數那裡沒有參數,所以是 0,如果是 1 個參數就是 Function1,系統最多提供了 22 個參數,再多的就需要自己定義擴展了。
好傢夥,那我們如果來個 for 循環,那不是創建了一堆實例對象?這時候 inline 就可以起作用了,編譯的時候直接把調用代碼複製替換進去。
我們來修改一下,加個 inline 關鍵字在看下效果:
然後再次編譯下看看:
可以看到,直接把原本的調用 copy 到調用處了。這樣就不會編譯為 FunctionX 類,減少了運行時的對象創建開銷。
那我是不是可以全部都弄成內聯了?但是這樣就又有了個問題。
在 println 加了個 return ,這樣就會導致下面的列印 「運行完成2」和「結束」都無法運行,這很明顯不是我們想要的,解決方法也很簡單,我們在 return 處加個 @label 就可以了。
不過 Kotlin 也有另一種方式來限制在 lambda 中直接 return,那就是使用 noinline 或 crossinline 。
如果你只是想內聯函數的某些 lamda 表達式被內聯,其他的不允許內聯操作的話可以使用 noinline 。
如上圖,middle 加了 noinline 後,return 報錯了,已經不能直接進行 return 操作,return@label 還是可以的。
那問題又來了,直接改成 noinline 的話,那不是又變成搞了一堆對象出來了?還有沒其他方法?Kotlin 還提供了一個 crossline 關鍵字。
把上面的 noinline 的例子改成 crossline ,來對比下編譯後的文件
從上面可以看得出,crossline 不會搞出一堆對象。
為了減少使用高階函數帶來的一些運行時的效率損失,可以使用inline 來標記一個函數為內聯函數。
內聯函數在編譯後會把代碼都插入到調用函數的地方,所以可能導致最終的代碼增加,所以必須避免內聯過大函數才能使內聯函數性能提升。
另外我們可以用 noinline 和 crossinline 來限制內聯函數中的lambda 直接調用 return 返回,避免出現預料之外的結果。
剛才我提到了編譯後的文件,那麼在 AndroidStudio 上如何快速查看呢?