Kotlin中關(guān)于內(nèi)聯(lián)函數(shù)的一些理解分享
前言
看了很多博客,才明白了內(nèi)聯(lián)的含義,其實(shí)最根本的就是將寫在別處的代碼拷貝到你現(xiàn)在執(zhí)行的方法中,相當(dāng)于在一個(gè)方法中執(zhí)行,java的方法執(zhí)行是需要壓棧出棧的對(duì)吧,如果是兩三個(gè)方法那就是兩三次的壓棧出棧,為了節(jié)省這個(gè)操作,提高一定的效率,kotlin就出了這么個(gè)函數(shù)。但又想想,如果是個(gè)超級(jí)大的函數(shù),考來(lái)考去的也是很麻煩啊,所以這東西需要自己權(quán)衡吧,遵守單一職責(zé),降低代碼圈發(fā)雜度才是根本。
內(nèi)聯(lián)函數(shù)的理解
inline函數(shù)(內(nèi)聯(lián)函數(shù))從概念上講是編譯器使用函數(shù)實(shí)現(xiàn)的真實(shí)代碼來(lái)替換每一次的函數(shù)調(diào)用,帶來(lái)的最直接的好處就是節(jié)省了函數(shù)調(diào)用的開銷,而缺點(diǎn)就是增加了所生成字節(jié)碼的尺寸。基于此,在代碼量不是很大的情況下,我們是否有必要將所有的函數(shù)定義為內(nèi)聯(lián)?讓我們分兩種情況進(jìn)行說(shuō)明:
- 將普通函數(shù)定義為內(nèi)聯(lián):眾所周知,JVM內(nèi)部已經(jīng)實(shí)現(xiàn)了內(nèi)聯(lián)優(yōu)化,它會(huì)在任何可以通過(guò)內(nèi)聯(lián)來(lái)提升性能的地方將函數(shù)調(diào)用內(nèi)聯(lián)化,并且相對(duì)于手動(dòng)將普通函數(shù)定義為內(nèi)聯(lián),通過(guò)JVM內(nèi)聯(lián)優(yōu)化所生成的字節(jié)碼,每個(gè)函數(shù)的實(shí)現(xiàn)只會(huì)出現(xiàn)一次,這樣在保證減少運(yùn)行時(shí)開銷的同時(shí),也沒(méi)有增加字節(jié)碼的尺寸;所以我們可以得出結(jié)論,對(duì)于普通函數(shù),我們沒(méi)有必要將其聲明為內(nèi)聯(lián)函數(shù),而是交給JVM自行優(yōu)化。
- 將帶有l(wèi)ambda參數(shù)的函數(shù)定義為內(nèi)聯(lián):是的,這種情況下確實(shí)可以提高性能;但在使用的過(guò)程中,我們會(huì)發(fā)現(xiàn)它是有諸多限制的,讓我們從下面的例子開始展開說(shuō)明:
inline fun doSomething(action: () -> Unit) {
println("Before doSomething...")
action()
println("After doSomething...")
}
假如我們這樣調(diào)用doSomething:
fun main(args: Array<String>) {
doSomething {
pringln("Hello World")
}
}
上面的調(diào)用會(huì)被編譯成:
fun main(args: Array<String>) {
println("Before doSomething...")
println("Hello World")
println("After doSomething...")
}
從上面編譯的結(jié)果可以看出,無(wú)論doSomething函數(shù)還是action參數(shù)都被內(nèi)聯(lián)了,很棒,那讓我們換一種調(diào)用方式:
fun main(args: Array<String>) {
val action:() -> Unit = { println("Hello World") }
doSomething(action)
}
上面的調(diào)用會(huì)被編譯成:
fun main(args: Array<String>) {
println("Before doSomething...")
action()
println("After doSomething...")
}
doSomething函數(shù)被內(nèi)聯(lián),而action參數(shù)沒(méi)有被內(nèi)聯(lián),這是因?yàn)橐院瘮?shù)型變量的形式傳遞給doSomething的lambda在函數(shù)的調(diào)用點(diǎn)是不可用的,只有等到doSomething被內(nèi)聯(lián)后,該lambda才可以正常使用。
通過(guò)上面的例子,我們對(duì)lambda表達(dá)式何時(shí)被內(nèi)聯(lián)做一下簡(jiǎn)單的總結(jié):
- 當(dāng)lambda表達(dá)式以參數(shù)的形式直接傳遞給內(nèi)聯(lián)函數(shù),那么lambda表達(dá)式的代碼會(huì)被直接替換到最終生成的代碼中。
- 當(dāng)lambda表達(dá)式在某個(gè)地方被保存起來(lái),然后以變量形式傳遞給內(nèi)聯(lián)函數(shù),那么此時(shí)的lambda表達(dá)式的代碼將不會(huì)被內(nèi)聯(lián)。
上面對(duì)lambda的內(nèi)聯(lián)時(shí)機(jī)進(jìn)行了討論,消化片刻后讓我們?cè)倏醋詈笠粋€(gè)例子:
inline fun doSomething(action: () -> Unit, secretAction: () -> Unit) {
action()
doSomethingSecret(secretAction)
}
fun doSomethingSecret(secretAction: () -> Unit) {
}
上面的例子是否有問(wèn)題?是的,編譯器會(huì)拋出“Illegal usage of inline-parameter”的錯(cuò)誤,這是因?yàn)镵otlin規(guī)定內(nèi)聯(lián)函數(shù)中的lambda參數(shù)只能被直接調(diào)用或者傳遞給另外一個(gè)內(nèi)聯(lián)函數(shù),除此之外不能作為他用;那我們?nèi)绻_實(shí)想要將某一個(gè)lambda傳遞給一個(gè)非內(nèi)聯(lián)函數(shù)怎么辦?我們只需將上述代碼這樣改造即可:
inline fun doSomething(action: () -> Unit, noinline secretAction: () -> Unit) {
action()
doSomethingSecret(secretAction)
}
fun doSomethingSecret(secretAction: () -> Unit) {
}
很簡(jiǎn)單,在不需要內(nèi)聯(lián)的lambda參數(shù)前加上noinline修飾符就可以了。
以上便是我對(duì)內(nèi)聯(lián)函數(shù)的全部理解,通過(guò)掌握該特性的運(yùn)行機(jī)制,相信大家可以做到在正確的時(shí)機(jī)使用該特性,而非濫用或因恐懼棄而不用。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
android studio實(shí)現(xiàn)簡(jiǎn)單考試應(yīng)用程序?qū)嵗a詳解
這篇文章主要介紹了android studio實(shí)現(xiàn)簡(jiǎn)單考試應(yīng)用程序,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-03-03
Android編程實(shí)現(xiàn)Listview點(diǎn)擊展開和隱藏的方法
這篇文章主要介紹了Android編程實(shí)現(xiàn)Listview點(diǎn)擊展開和隱藏的方法,涉及Android中Listview的響應(yīng)點(diǎn)擊與樣式變換相關(guān)操作技巧,需要的朋友可以參考下2015-12-12
Android實(shí)現(xiàn)自動(dòng)文本框提示功能
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)自動(dòng)文本框提示功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10
Android動(dòng)畫之小球擬合動(dòng)畫實(shí)例
這篇文章主要介紹了Android動(dòng)畫之小球擬合動(dòng)畫實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-07-07

