日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Kotlin难点解析:extension和this指针

發(fā)布時(shí)間:2025/4/16 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Kotlin难点解析:extension和this指针 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
擴(kuò)展(extension)是Kotlin語言中使用非常簡單的一個(gè)特性。這篇文章并不是要講解擴(kuò)展的基本用法,而是解決在一些復(fù)雜場景中,擴(kuò)展容易讓人產(chǎn)生迷惑的一些問題。除了擴(kuò)展,本篇文章還將講解this指針在Kotlin語言中的基礎(chǔ)用法。

擴(kuò)展函數(shù)難點(diǎn)解析

大多數(shù)場景下,你都能輕松搞定Kotlin擴(kuò)展。可是,看看下面這個(gè)題目,你還能脫口而出,告訴我答案是什么嗎?

open class E {}open class E1: E() {}open class A {open fun E.f() {println("E.f in A")}open fun E1.f() {println("E1.f in A")}fun call(e: E) {e.f()} }class A1: A() {override fun E.f() {println("E.f in A1")}override fun E1.f() {println("E1.f in A1")} }fun main(args: Array<String>) {// a)A().call(E())// b)A1().call(E())// c)A().call(E())// d)A().call(E1()) }

問題:請(qǐng)告訴a,b,c,d位置代碼執(zhí)行的輸出結(jié)果是什么?

對(duì)于這個(gè)問題,恐怕你在紙上寫寫畫畫半天也不一定能給出正確答案吧。關(guān)于這個(gè)問題,其實(shí)我之前的一篇文章 [ [Kotlin] Lambda and Extension](https://www.jianshu.com/p/d7a... 中有提到過。可是,我認(rèn)為這篇文章關(guān)于這部分的解釋不夠清晰,有必要再詳細(xì)闡述一次。

Ok,let's started。

為了解決這個(gè)問題,官方提出了兩個(gè)新的概念:dispatch receiverextension receiver

  • dispatch receiver:中文翻譯為分發(fā)接收者。所謂的分發(fā)接收者,就是聲明這個(gè)擴(kuò)展方法所在的類。即:在哪個(gè)類中聲明,那個(gè)類就是你的分發(fā)接收者。
  • extension receiver:中文翻譯為擴(kuò)展接收者。所謂的擴(kuò)展接收者,就是你實(shí)際擴(kuò)展的那個(gè)類。舉個(gè)例子:你針對(duì)Int類擴(kuò)展了一個(gè)方法add,這個(gè)add方法的擴(kuò)展接收者就是Int類實(shí)例。

為了簡化,這里我們將dispatch receiver簡稱為DR,將extension receiver簡稱為ER

還記得多態(tài)的概念嗎?多態(tài)是一種運(yùn)行時(shí)概念,即對(duì)象的類型要等到運(yùn)行時(shí)才能最終確定。因此,一些語言中也將多態(tài)叫做類型延遲加載。解決上面這個(gè)問題我們需要關(guān)注就是擴(kuò)展函數(shù)是否會(huì)產(chǎn)生多態(tài)行為。

這里我們將產(chǎn)生多態(tài)行為的技術(shù)叫做動(dòng)態(tài)解析,與之相反的行為稱之為靜態(tài)解析

為了解決上面的問題,你需要記住下面這個(gè)規(guī)則:

  • DR類型是動(dòng)態(tài)解析的
  • 與之相反,ER類型是靜態(tài)解析的

先看上面例子的a、b部分,很顯然:

  • a代碼中f函數(shù)的DR是類A,ER是類E
  • b代碼中f函數(shù)的DR是類A1,ER是類E

參照上面的規(guī)則,由于DR類型是動(dòng)態(tài)解析的。在A1類中我們重寫了E的擴(kuò)展函數(shù)f,運(yùn)行時(shí)最終會(huì)執(zhí)行A1類中擴(kuò)展的f方法。a部分很明顯會(huì)輸出A類中擴(kuò)展的f方法。因此,最終的輸出結(jié)果如下:

E.f in A E.f in A1

繼續(xù)看c、d部分,c、d部分的DR都是A,而對(duì)于ER,c、d分別是E、E1。參照上面的規(guī)則,ER是靜態(tài)解析的。在call方法聲明的地方,我們傳入的對(duì)象類型是E,這就決定了無論擴(kuò)展方法是來自E還是其子類,將始終執(zhí)行E類的擴(kuò)展方法。因此,c、d部分將輸出同樣的結(jié)果:

E.f in A E.f in A

由此可見,如果你牢記上述兩條規(guī)則,解決問題將變得非常容易。為了加強(qiáng)你的記憶,我用一個(gè)表格總結(jié)上面的知識(shí)點(diǎn):

-DRER
概念擴(kuò)展方法聲明所在的類聲明擴(kuò)展方法的類
解析方式動(dòng)態(tài)解析靜態(tài)解析

PS:由于新版本Kotlin中針對(duì)擴(kuò)展函數(shù)也加入了override關(guān)鍵字,這非常有助于DR和ER的理解。如果你在使用Kotlin,強(qiáng)烈建議你更新到最新版本。

不太一樣的this指針

在Java語言中,如果你在內(nèi)部類中需要外部類的引用可以將this寫在類名后面。可是,試試看Kotlin,果斷不行。

為了獲得外部類的引用,Kotlin語言引入了@符號(hào)。舉個(gè)例子:

class Outer {inner class Inner {fun f() {println(this@Outer)}} }

可以看到,為了獲取外部類的引用,只需要在@后面接外部類的名稱即可。

如果對(duì)應(yīng)一個(gè)擴(kuò)展函數(shù),this引用指向是什么呢?先說答案,擴(kuò)展函數(shù)中的this指針指向ER,即實(shí)際擴(kuò)展的那個(gè)類對(duì)象。

fun Outer.foo() {println(this) }

這里的this指向foo函數(shù)的接收者Outer類實(shí)例。

this指針還有一種場景是用在lambda表達(dá)式中,這是一種比較特殊的使用場景。lambda表達(dá)式本身沒有任何接收者,如果是在全局聲明一個(gè)lambda表達(dá)式,將不能使用this指針。而如果是在某個(gè)類或者擴(kuò)展方法中使用this指針,將指向?qū)嶋H所在類或者擴(kuò)展方法的接收者。

如果你習(xí)慣了Kotlin語言的這種表達(dá)方式,this指針的指向就不再是一個(gè)問題了。在你習(xí)慣這種用法之前,我用一個(gè)表格簡單總結(jié)一下this指針的用法:

位置指向
類中默認(rèn)指向當(dāng)前類實(shí)例,使用@操作符指向具體外部類實(shí)例
擴(kuò)展函數(shù)默認(rèn)指向擴(kuò)展函數(shù)的接收者
lambda表達(dá)式默認(rèn)指向?qū)嶋H所在類實(shí)例或所在擴(kuò)展函數(shù)的接收者

總結(jié)

關(guān)于擴(kuò)展,大多數(shù)情況下,你不會(huì)遇到文章開頭那種復(fù)雜的情況。如果遇到了這種情況,只要清楚地區(qū)分DR和ER,并牢記DR和ER的解析方式,就能輕松應(yīng)對(duì)了。對(duì)于this指針,與Java語言不一樣的地方是,為了引用具體類的實(shí)例,Kotlin語言使用@符號(hào)。個(gè)人認(rèn)為,這種表述方式更自然。如果遇到某些比較復(fù)雜的情況,只需要弄清楚接收者,問題就引刃而解了。

歡迎加入Kotlin交流群

如果你也喜歡Kotlin語言,歡迎加入我的Kotlin交流群: 329673958 ,一起來參與Kotlin語言的推廣工作。

編程,我們是認(rèn)真的!

關(guān)注歐陽鋒工作室公眾號(hào),你想要的都在這里:

總結(jié)

以上是生活随笔為你收集整理的Kotlin难点解析:extension和this指针的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。