Kotlin擴(kuò)展方法超詳細(xì)介紹
前言
在這一節(jié)為大家繼續(xù)帶來 Kotlin 中的一些高級的內(nèi)容:Kotlin 中的 Kotlin 擴(kuò) 展(Extensions)。
Kotlin 能夠擴(kuò)展一個類的新功能而無需繼承該類。 例如,你可以為一個你不 能修改的來自第三方庫中的類編寫一個新的函數(shù)。 這個新增的函數(shù)就像那個 原始類本來就有的函數(shù)一樣,可以用普通的方法調(diào)用。 這種機(jī)制稱為 擴(kuò)展 函數(shù) 。此外,也有 擴(kuò)展屬性 , 允許你為一個已經(jīng)存在的類添加新的屬 性。想想是不是感覺很瘋狂呢?那接下來就往我們開啟這種瘋狂吧。
一、擴(kuò)展方法
Kotlin 的擴(kuò)展函數(shù)可以讓你作為一個類成員進(jìn)行調(diào)用的函數(shù),但是是定義在這 個類的外部。這樣可以很方便的擴(kuò)展一個已經(jīng)存在的類,為它添加額外的方 法。在 Kotlin 源碼中,有大量的擴(kuò)展函數(shù)來擴(kuò)展 Java,這樣使得 Kotlin 比 Java 更方便使用,效率更高。
1.擴(kuò)展方法的原型
2.擴(kuò)展方法的使用
在 Kotlin 中使用
class Jump { fun test() { println("jump test") //在被擴(kuò)展的類中使用 doubleJump(1f) } } fun Jump.doubleJump(howLong: Float): Boolean { println("jump:$howLong") println("jump:$howLong") return true } Jump().doubleJump(2f) //在被擴(kuò)展類的外部使用 Jump().test()
在 Java 中使用
在 Java 中調(diào)用 Kotlin 擴(kuò)展,需要通過擴(kuò)展所在的文件名+.的方式進(jìn)行調(diào)用:
KotlinExtensionKt.doubleJump(new Jump(), 2.0f);
另外,需要注意的是我們需要為這個方法傳遞它被擴(kuò)展類的對象來作為接受者,為什么要傳遞接 受者對象,這是由擴(kuò)展的實(shí)現(xiàn)原理所決定的,在原理解析部分會講解。
二、Kotlin擴(kuò)展方法實(shí)現(xiàn)原理
在體驗(yàn)到 Kotlin 擴(kuò)展帶個我們高效編程的同時,我們不禁要問自己幾個問 題:
Kotlin 的擴(kuò)展是怎么實(shí)現(xiàn)的?
Kotlin 的擴(kuò)展會不是有性能問題?
接下來我們就從 Kotlin 反編譯出 Java 代碼上來一探究竟:
fun main() { val test = mutableListOf(1, 2, 3) test.swap(1, 2) println(test) } fun MutableList<Int>.swap(index1: Int, index2: Int) { val tmp = this[index1] this[index1] = this[index2] this[index2] = tmp }
反編譯出 Java 源碼
public final class KotlinExtensionKt { public static final void main() { List test = CollectionsKt.mutableListOf(new Integer[]{1, 2, 3}); swap(test, 1, 2); boolean var1 = false; System.out.println(test); } // $FF: synthetic method public static void main(String[] var0) { main(); } public static final void swap(@NotNull List $this$swap, int index1, int index2) { Intrinsics.checkParameterIsNotNull($this$swap, "$this$swap"); int tmp = ((Number)$this$swap.get(index1)).intValue(); $this$swap.set(index1, $this$swap.get(index2)); $this$swap.set(index2, tmp); } }
從反編譯出的 Java 源碼分析,擴(kuò)展函數(shù)的實(shí)現(xiàn)非常簡單,它沒有修改接受者類型的成員, 僅僅 是通過靜態(tài)方法來實(shí)現(xiàn)的。所以我們不必?fù)?dān)心擴(kuò)展函數(shù)會帶來額外的性能消耗。
三、泛型擴(kuò)展方法
為了考慮到擴(kuò)展函數(shù)的通用型,我們可以借助上面課程中學(xué)習(xí)到的泛型,來 為擴(kuò)展方法進(jìn)行泛型化改造,以 fun MutableList.swap(index1: Int, index2: Int)為例,接下來我們?yōu)樗M(jìn)行泛型化改造:
//泛型化擴(kuò)展函數(shù) fun <T> MutableList<T>.swap1(index1: Int, index2: Int) { val tmp = this[index1] this[index1] = this[index2] this[index2] = tmp } val test2 = mutableListOf("Android Q", "Android N", "Android M") test2.swap1(0,1) println(test2)
四、擴(kuò)展屬性
擴(kuò)展屬性提供了一種方法能通過屬性語法進(jìn)行訪問的 API 來擴(kuò)展。盡管它們 被叫做屬性,但是它們不能擁有任何狀態(tài),它不能添加額外的字段到現(xiàn)有的 Java 對象實(shí)例。
//為 String 添加一個 lastChar 屬性,用于獲取字符串的最后一個字符 val String.lastChar: Char get() = this.get(this.length - 1) ///為 List 添加一個 last 屬性用于獲取列表的最后一個元素,this 可以省略 val <T>List<T>.last: T get() = get(size - 1) val listString = listOf("Android Q", "Android N", "Android M") println("listString.last${listString.last}")
五、為伴生對象添加擴(kuò)展
如果一個類定義了伴生對象 ,那么我們也可以為伴生對象定義擴(kuò)展函數(shù)與屬性:
class Jump { companion object {} } fun Jump.Companion.print(str: String) { println(str) } Jump.print("伴生對象的擴(kuò)展")
就像伴生對象的常規(guī)成員一樣:可以只使用類名作為限定符來調(diào)用伴生對象 的擴(kuò)展成員;
六、Kotlin 中常用的擴(kuò)展
在 Kotlin 的源碼中定義了大量的擴(kuò)展,比如:let,run,apply,了解并運(yùn)用這些 函數(shù)能幫我們提高編碼效率,接下來就往我們一起揭開這些擴(kuò)展函數(shù)的神秘面紗吧!
let 擴(kuò)展
函數(shù)原型:
fun <T, R> T.let(f: (T) -> R): R = f(this)
let 擴(kuò)展函數(shù)的實(shí)際上是一個作用域函數(shù),當(dāng)你需要去定義一個變量在一個特定的作用域范圍內(nèi),那么let 函數(shù)是一個不錯的選擇;let 函數(shù)另一個作用就 是可以避免寫一些判斷 null 的操作。
fun testLet(str: String?) { //限制 str2 的作用域 str.let { val str2 = "let 擴(kuò)展" println(it + str2) } // println(str2)//報錯 //避免為 null 的操作 str?.let { println(it.length) } }
run 擴(kuò)展
函數(shù)原型:
fun <T, R> T.run(f: T.() -> R): R = f()
run 函數(shù)只接收一個 lambda 函數(shù)為參數(shù),以閉包形式返回,返回值為最后一 行的值或者指定的 return 的表達(dá)式,在 run 函數(shù)中可以直接訪問實(shí)例的公有屬性和方法。
data class Room(val address: String, val price: Float, val size: Float) fun testRun(room: Room) { room.run { println("Room:$address,$price,$size") } }
apply 擴(kuò)展
函數(shù)原型:
fun <T> T.apply(f: T.() -> Unit): T { f(); return this }
apply 函數(shù)的作用是:調(diào)用某對象的 apply 函數(shù),在函數(shù)范圍內(nèi),可以任意調(diào) 用該對象的任意方法,并返回該對象。
從結(jié)構(gòu)上來看 apply 函數(shù)和 run 函數(shù)很像,唯一不同點(diǎn)就是它們各自返回的 值不一樣,run 函數(shù)是以閉包形式返回最后一行代碼的值,而 apply 函數(shù)的返 回的是傳入對象的本身。
apply 一般用于一個對象實(shí)例初始化的時候,需要對對象中的屬性進(jìn)行賦值。 或者動態(tài) inflate 出一個 XML 的 View 的時候需要給 View 綁定數(shù)據(jù)也會用 到,這種情景非常常見。
fun testApply() { ArrayList<String>().apply { add("testApply") add("testApply") add("testApply") println("$this") }.let { println(it) } }
七、案例
使用 Kotlin 擴(kuò)展為控件綁定監(jiān)聽器減少模板代碼
定義擴(kuò)展
//為 Activity 添加 find 擴(kuò)展方法,用于通過資源 id 獲取控件 fun <T : View> Activity.find(@IdRes id: Int): T { return findViewById(id) } //為 Int 添加 onClick 擴(kuò)展方法,用于為資源 id 對應(yīng)的控件添加 onClick 監(jiān)聽 fun Int.onClick(activity: Activity, click: () -> Unit) { activity.find<View>(this).apply { setOnClickListener { click() } } }
應(yīng)用擴(kuò)展
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val textView = find<TextView>(R.id.test) R.id.test.onClick(this) { textView.text = "Kotlin 泛型" } } }
在這個案例中我們通過兩個擴(kuò)展方法,大大減少了我們在獲取控件,以及為 控件綁定 onClick 監(jiān)聽時候的模板代碼,而且代碼可讀性更高,更加直觀, 這便是 Kotlin 擴(kuò)展的強(qiáng)大之處。
Kotlin 擴(kuò)展的應(yīng)用案例遠(yuǎn)不止這些,需要大家在下去之后能夠活學(xué)活用,來發(fā) 掘?qū)儆谀阕约旱?Kotlin 擴(kuò)展吧。
到此這篇關(guān)于Kotlin擴(kuò)展方法超詳細(xì)介紹的文章就介紹到這了,更多相關(guān)Kotlin擴(kuò)展內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android?縮放動畫?ScaleAnimation的使用小結(jié)
ScaleAnimation即縮放動畫,應(yīng)用場景特別多,比如常見的隱藏菜單點(diǎn)擊顯示,這篇文章主要介紹了Android?縮放動畫?ScaleAnimation的使用小結(jié),需要的朋友可以參考下2024-03-03Android懸浮按鈕點(diǎn)擊返回頂部FloatingActionButton
這篇文章主要為大家詳細(xì)介紹了Android懸浮按鈕FloatingActionButton點(diǎn)擊回到頂部的實(shí)現(xiàn)代碼,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02Android 仿高德地圖可拉伸的BottomSheet的示例代碼
這篇文章主要介紹了Android 仿高德地圖可拉伸的BottomSheet的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-07-07Android使用animator實(shí)現(xiàn)fragment的3D翻轉(zhuǎn)效果
這篇文章主要為大家詳細(xì)介紹了Android使用animator實(shí)現(xiàn)fragment的3D翻轉(zhuǎn)效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12Android ViewGroup事件分發(fā)和處理源碼分析
這篇文章主要為大家介紹了Android ViewGroup事件分發(fā)和處理源碼分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-02-02android 中win10 使用uwp控件實(shí)現(xiàn)進(jìn)度條Marquez效果
這篇文章主要介紹了android 中win10 使用uwp控件實(shí)現(xiàn)進(jìn)度條Marquez效果,需要的朋友可以參考下2017-06-06Android開發(fā)之多媒體文件獲取工具類實(shí)例【音頻,視頻,圖片等】
這篇文章主要介紹了Android開發(fā)之多媒體文件獲取工具類,結(jié)合實(shí)例形式分析了Android獲取音頻,視頻及圖片等多媒體資源的相關(guān)操作技巧,需要的朋友可以參考下2017-10-10Android自定義多節(jié)點(diǎn)進(jìn)度條顯示的實(shí)現(xiàn)代碼(附源碼)
這篇文章主要介紹了Android自定義多節(jié)點(diǎn)進(jìn)度條顯示的實(shí)現(xiàn)代碼,非常不錯,具有參考借鑒價值,需要的朋友可以參考下2017-03-03Kotlin設(shè)計(jì)模式之委托模式使用方法詳解
Kotlin提供了兩個本機(jī)功能來實(shí)現(xiàn)委托模式,第一個是接口委托(例如策略模式),另一種是屬性委托,它專注于類成員/屬性(例如延遲加載、observable等),它們共同提供了一組豐富而簡潔的功能,通過本博客,您將了解在什么情況下使用此模式2023-09-09