kotlin—匿名函數(shù)及其實現(xiàn)原理

1霉撵、匿名函數(shù)語法

匿名函數(shù)就是沒有名稱的函數(shù)浙于,它除了沒有名稱之外芹助,其他與具名函數(shù)是一樣的堂湖。
你們函數(shù)的語法如下:

fun([args]) [:returnType]{
    [body]
} 

args:就是函數(shù)參數(shù)列表,與具名函數(shù)的參數(shù)是一樣的規(guī)則
returnType:函數(shù)的返回類型状土,與具名函數(shù)的參數(shù)是一樣的規(guī)則

匿名函數(shù)屬于函數(shù)類型

2无蜂、匿名原理

你們函數(shù)的實現(xiàn)原理與kotlin—lambda及其原理差不多一樣的原理,它們都生成一個匿名類蒙谓,通過匿名類的來實現(xiàn)匿名函數(shù)的對應方法體斥季。
匿名函數(shù)也是根據(jù)函數(shù)參數(shù)個數(shù)實現(xiàn)Function系列的接口,我們通過例子來分析其原理:
舉例:

class TestClosure {
    val b = 20
    val sum : () -> Int = fun() : Int {
        return b + 10
    }
}

TestClosure 中聲明了一個匿名函數(shù)sum變量累驮,它使用外部TestClosure 類的成員變量b酣倾。
編譯TestClosure 之后,除了生成TestClosure.class之外谤专,還生成了TestClosuresum1.class躁锡,它是匿名函數(shù)的對應的匿名類,我們通過javac -c -v -p TestClosuresum1.class反編譯看看其偽代碼:

final class com.wyx.tcanvas.test.delegate.TestClosure$sum$1 extends kotlin.jvm.internal.Lambda implements kotlin.jvm.functions.Function0<java.lang.Integer>
  //省略.....
{
//聲明TestClosure對象置侍,即匿名類持有外部類的引用
final com.wyx.tcanvas.test.delegate.TestClosure this$0;
    descriptor: Lcom/wyx/tcanvas/test/delegate/TestClosure;
    flags: (0x1010) ACC_FINAL, ACC_SYNTHETIC

//匿名類構造函數(shù)映之,參數(shù)是外部類的引用 com.wyx.tcanvas.test.delegate.TestClosure$sum$1(com.wyx.tcanvas.test.delegate.TestClosure);
    descriptor: (Lcom/wyx/tcanvas/test/delegate/TestClosure;)V
    flags: (0x0000)
    Code:
      stack=2, locals=2, args_size=2
         //0-3:將外部類引用賦值給this$0
         0: aload_0
         1: aload_1
         2: putfield      #13                 // Field this$0:Lcom/wyx/tcanvas/test/delegate/TestClosure;
         5: aload_0
         6: iconst_0
         7: invokespecial #16                 // Method kotlin/jvm/internal/Lambda."<init>":(I)V
        10: return
      //省略......
  
  //匿名函數(shù)的真實方法體
  public final java.lang.Integer invoke();
    descriptor: ()Ljava/lang/Integer;
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=1, args_size=1
         //0-13:調用this$0.getgetB() + 10,并返回蜡坊,其實就是匿名函數(shù)的b + 10
         0: aload_0
         1: getfield      #13                 // Field this$0:Lcom/wyx/tcanvas/test/delegate/TestClosure;
         4: invokevirtual #28                 // Method com/wyx/tcanvas/test/delegate/TestClosure.getB:()I
         7: bipush        10
         9: iadd
        10: invokestatic  #34                 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        13: areturn
      //省略......
  
  //實現(xiàn)的Function接口invoke方法
  public java.lang.Object invoke();
    descriptor: ()Ljava/lang/Object;
    flags: (0x1041) ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=1, locals=1, args_size=1
          //調用匿名函數(shù)的實體invoke方法并返回
         0: aload_0
         1: invokevirtual #37                 // Method invoke:()Ljava/lang/Integer;
         4: areturn
     //省略.....
}
//省略.....

通過反編譯之后匿名類的偽代碼杠输,我們發(fā)現(xiàn)其實匿名函數(shù)與kotlin—lambda及其原理的原理是一樣的。
匿名函數(shù)會生成一個內部匿名類秕衙,匿名類繼承l(wèi)ambda類同時實現(xiàn)Function系列接口蠢甲,F(xiàn)unction接口的invoke方法調用匿名函數(shù)的真實實現(xiàn)函數(shù)invoke。
如果匿名函數(shù)沒有引用外部類的成員則使用匿名類單例對象的据忘;如果匿名函數(shù)使用了外部類的成員則內部會持有外部類的引用鹦牛,在匿名函數(shù)的實現(xiàn)函數(shù)invoke中通過持有外部類的引用來調用外部類的成員搞糕。

3、總結

匿名函數(shù)會生成一個內部匿名類能岩,匿名類繼承l(wèi)ambda類同時實現(xiàn)Function系列接口寞宫,F(xiàn)unction接口的invoke方法調用匿名函數(shù)的真實實現(xiàn)函數(shù)invoke。
如果匿名函數(shù)沒有引用外部類的成員則使用匿名類單例對象的方式拉鹃;如果匿名函數(shù)使用了外部類的成員則內部會持有外部類的引用辈赋,在匿名函數(shù)的實現(xiàn)函數(shù)invoke中通過持有外部類的引用來調用外部類的成員。
匿名函數(shù)與lambda一樣要注意不要濫用膏燕,因為它會生成額外的匿名類class文件钥屈,在使用時會創(chuàng)建匿名類實例對象,增加額外的空間和執(zhí)行時間損耗坝辫,如果只是用匿名函數(shù)代表一個函數(shù)并執(zhí)行此函數(shù)其實并非是明智的選擇篷就。
匿名函數(shù)與lambda還需要注意的是,如果引用了外部類的成員近忙,那么它們內部會持有外部類的引用竭业,如果使用不當會引起內存泄漏,比較典型的就是Android中的Activity使用匿名類導致的內存泄漏——解決方案是使用弱引用等

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末及舍,一起剝皮案震驚了整個濱河市未辆,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌锯玛,老刑警劉巖咐柜,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異攘残,居然都是意外死亡拙友,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進店門歼郭,熙熙樓的掌柜王于貴愁眉苦臉地迎上來遗契,“玉大人,你說我怎么就攤上這事病曾℃⑼荆” “怎么了?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵知态,是天一觀的道長。 經(jīng)常有香客問我立叛,道長负敏,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任秘蛇,我火速辦了婚禮其做,結果婚禮上顶考,老公的妹妹穿的比我還像新娘。我一直安慰自己妖泄,他們只是感情好驹沿,可當我...
    茶點故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蹈胡,像睡著了一般渊季。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上罚渐,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天却汉,我揣著相機與錄音,去河邊找鬼荷并。 笑死合砂,一個胖子當著我的面吹牛,可吹牛的內容都是我干的源织。 我是一名探鬼主播翩伪,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼谈息!你這毒婦竟也來了缘屹?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤黎茎,失蹤者是張志新(化名)和其女友劉穎囊颅,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體傅瞻,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡踢代,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了嗅骄。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片胳挎。...
    茶點故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖溺森,靈堂內的尸體忽然破棺而出慕爬,到底是詐尸還是另有隱情,我是刑警寧澤屏积,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布医窿,位于F島的核電站,受9級特大地震影響炊林,放射性物質發(fā)生泄漏姥卢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望独榴。 院中可真熱鬧僧叉,春花似錦、人聲如沸棺榔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽症歇。三九已至郎笆,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間当船,已是汗流浹背题画。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留德频,地道東北人苍息。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像壹置,于是被迫代替她去往敵國和親竞思。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,092評論 2 355

推薦閱讀更多精彩內容