一篇文章弄懂kotlin的擴(kuò)展方法
Usage
擴(kuò)展函數(shù)是 kotlin 的又一殺手锏功能,能夠在不修改源碼的基礎(chǔ)上,擴(kuò)展某些類(lèi)的能力,方便開(kāi)發(fā)。
例如這里演示了給 String 添加一個(gè)獲取第一個(gè)元素的方法。
fun String.first(): Char {
if (isEmpty()) {
throw NoSuchElementException("String is empty")
}
return this[0]
}
fun main(args: Array<String>) {
println("Hello,World".first())
}
這里需要額外注意的地方在于擴(kuò)展函數(shù)的方法體中,是能夠直接訪問(wèn)擴(kuò)展對(duì)象 public 的變量的。例如上面的方法里面,我們也可以這么寫(xiě):
fun String.first(): Char {
if (length < 1) {
throw NoSuchElementException("String is empty")
}
return this[0]
}
通過(guò) this 可以在方法內(nèi),訪問(wèn)擴(kuò)展對(duì)象,這里就是通過(guò) this[0] 拿到第一個(gè)字符的。
Under in hood
看上去很厲害哈,但他的原理卻非常簡(jiǎn)單。我們要時(shí)刻記住,kotlin JVM 是基于 JVM 開(kāi)發(fā)的,kotlin 源碼最后會(huì)變成字節(jié)碼而后被運(yùn)行。當(dāng)遇到語(yǔ)法上不太懂的地方,直接反編譯字節(jié)碼,或者 Decompile 成 Java 方法,就能洞察里面的玄機(jī)。
我們將上述代碼,Decompile 成 Java 后,就能發(fā)現(xiàn)里面的秘密。
public static final char first(@NotNull String $this$first){
Intrinsics.checkParameterIsNotNull($this$first, "$this$first");
if ($this$first.length() < 1) {
throw (Throwable)(new NoSuchElementException("String is empty"));
} else {
return $this$first.charAt(0);
}
}
原來(lái)是生成了一個(gè) public static final 的方法呀,不過(guò)這個(gè)生成是 kotlin 提供的語(yǔ)法糖,幫我們完成的。看到這個(gè)代碼,也解釋了為什么在擴(kuò)展對(duì)象方法內(nèi)部,能夠訪問(wèn)到擴(kuò)展對(duì)象的 public 成員。
重載與多態(tài)
擴(kuò)展方法能否被繼承呢,或者重載呢?我們來(lái)看看例子
open class Animal
class Dog : Animal()
fun Animal.desc() = "Animal"
fun Dog.desc() = "Dog"
fun main(args: Array<String>) {
println(Dog().desc())
var animal: Animal = Dog()
println(animal.desc())
}
// output:
// Dog
// Animal
如果擴(kuò)展方法能夠被重載,那么兩次都應(yīng)該輸出 Dog,我們還是和前面方法一樣,來(lái)看看真相。
@NotNull
public static final String desc(@NotNull Animal $this$desc) {
Intrinsics.checkParameterIsNotNull($this$desc, "$this$desc");
return "Animal";
}
@NotNull
public static final String desc(@NotNull Dog $this$desc) {
Intrinsics.checkParameterIsNotNull($this$desc, "$this$desc");
return "Dog";
}
可以看到實(shí)際生成了兩個(gè) desc 方法,里面的參數(shù)不動(dòng),所以這個(gè)方法的調(diào)用,只與擴(kuò)展對(duì)象本身有關(guān)系,在編譯時(shí)已經(jīng)確定,不存在多態(tài)。
擴(kuò)展屬性
這是一個(gè)很神奇的設(shè)定,kotlin 并不能真的給擴(kuò)展對(duì)象添加一個(gè)屬性,而只是提供了一個(gè)語(yǔ)法糖,什么意思呢?我們具體看看下面這個(gè)例子。
var String.first: Char
get() {
if (isEmpty()) {
throw NoSuchElementException(“String is empty”)
}
return this[0]
}
set(value) {
println(“set value to $value”)
}
fun main() {
“Hello, World”.first = ‘G'
println(“Hello,World”.first)
}
我們擴(kuò)展了 kotlin 的屬性,添加了一個(gè) first。我們可以分別給這個(gè)所謂的 first 屬性,注意是所謂的,添加 get 和 set 方法。然后我們可以通過(guò) = 和 . 來(lái)調(diào)用 set 和 get 方法,就像 main 方法中那樣。但實(shí)際上,最后并沒(méi)有生成 first 屬性,我們來(lái)看看反編譯過(guò)后的代碼。
public static final Char getFirst(@NotNull String $this$first) {
Intrinsics.checkParameterIsNotNull($this$first, "$this$first");
CharSequence var1 = (CharSequence)$this$first;
boolean var2 = false;
if (var1.length() == 0) {
throw (Throwable)(new NoSuchElementException("String is empty"));
} else {
return $this$first.charAt(0);
}
}
public static final void setFirst(@NotNull String $this$first, char value) {
Intrinsics.checkParameterIsNotNull($this$first, "$this$first");
String var2 = "set value to " + value;
boolean var3 = false;
System.out.println(var2);
}
看到?jīng)]有,實(shí)際上只是添加了 setFirst 和 getFirst 兩個(gè)方法,并沒(méi)有實(shí)際的屬性添加上去。這也是 kotlin 提供給我們的語(yǔ)法糖之一,糖要吃,但也要小心蛀牙哦!
好了,以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
android中創(chuàng)建通知欄Notification代碼實(shí)例
這篇文章主要介紹了android中創(chuàng)建通知欄Notification代碼實(shí)例,本文直接給出實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-05-05
Kotlin類(lèi)對(duì)象class初始化與使用
Kotlin 是一種追求簡(jiǎn)潔的語(yǔ)言,在類(lèi)上也下了不少功夫,放棄了很多c++ 中類(lèi)非常復(fù)雜的概念,其實(shí)對(duì)于類(lèi)可以這樣來(lái)理解,為了復(fù)用的方便性和完整性,我們把變量和函數(shù)組合在一起,形成了類(lèi)的概念2022-12-12
Android編程使用android-support-design實(shí)現(xiàn)MD風(fēng)格對(duì)話框功能示例
這篇文章主要介紹了Android編程使用android-support-design實(shí)現(xiàn)MD風(fēng)格對(duì)話框功能,涉及Android對(duì)話框、視圖、布局相關(guān)操作技巧,需要的朋友可以參考下2017-01-01
Android自定義Gradle插件的詳細(xì)過(guò)程
Groovy語(yǔ)言是一種jvm語(yǔ)言,最終也是編譯成class文件然后在jvm上執(zhí)行,所以所有的Java語(yǔ)言的特性Groovy都支持,我們可以完全混寫(xiě)Java和Groovy,對(duì)Android自定義Gradle插件相關(guān)知識(shí),感興趣的朋友跟隨小編一起看看吧2021-07-07
Android使用Rotate3dAnimation實(shí)現(xiàn)3D旋轉(zhuǎn)動(dòng)畫(huà)效果的實(shí)例代碼
利用Android的ApiDemos的Rotate3dAnimation實(shí)現(xiàn)了個(gè)圖片3D旋轉(zhuǎn)的動(dòng)畫(huà),圍繞Y軸進(jìn)行旋轉(zhuǎn),還可以實(shí)現(xiàn)Z軸的縮放。點(diǎn)擊開(kāi)始按鈕開(kāi)始旋轉(zhuǎn),點(diǎn)擊結(jié)束按鈕停止旋轉(zhuǎn)。2018-05-05
Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器(可以實(shí)現(xiàn)連續(xù)計(jì)算)
這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)簡(jiǎn)易計(jì)算器,可以實(shí)現(xiàn)連續(xù)計(jì)算,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-03-03
android利用handler實(shí)現(xiàn)打地鼠游戲
這篇文章主要為大家詳細(xì)介紹了android利用handler實(shí)現(xiàn)打地鼠游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-11-11
Android ToolBar整合實(shí)例使用方法詳解
這篇文章主要為大家詳細(xì)介紹了Android ToolBar整合實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-02-02
TabLayout實(shí)現(xiàn)ViewPager指示器的方法
這篇文章主要為大家詳細(xì)介紹了TabLayout實(shí)現(xiàn)ViewPager指示器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06

