Android(Java) | 你知道嗎问畅?Java匿名內(nèi)部類其實是有“名字”和構(gòu)造方法的娃属!

要點

  • 匿名類的概念和用法
  • 語言規(guī)范以及語言的橫向?qū)Ρ鹊?/li>
  • 內(nèi)存泄漏的切入點

總結(jié)

  • 沒有人類認(rèn)知意義上的名字
  • 只能繼承一個父類或?qū)崿F(xiàn)一個接口
  • 父類是非靜態(tài)的類型六荒,則需父類外部實例來初始化
  • 如果定義在非靜態(tài)作用域內(nèi),會引用外部類實例
  • 只能捕獲外部作用域內(nèi)的final變量
  • 創(chuàng)建時只有單一方法的接口可以用Lambda轉(zhuǎn)換



a.匿名內(nèi)部類的名字

表面上是沒有引用名的矾端,
但其實是有用于定位的“名字”掏击,

如上代碼,
new Foo()在定義的時候秩铆,
重寫了bar()這個方法砚亭,
如此一來new Foo(){...}這里就是一個匿名內(nèi)部類了;

吶這個匿名內(nèi)部類殴玛,實際上在字節(jié)碼中是會定義出來的捅膘,!9鏊凇篓跛!
定義出來一個用于定位的“名字”,
這個“名字”可見上面代碼的第二行坦刀,
com.bennyhuo.iiv.ch1.”即代碼包名愧沟,
OuterClass$1”即外部內(nèi)名$1
1代表這個匿名內(nèi)部類鲤遥,
是前綴的外部類中沐寺,定義的第一個匿名內(nèi)部類,
再創(chuàng)建第二個匿名內(nèi)部類 就是$2了盖奈;

所以匿名內(nèi)部類普通類一樣混坞,是可以加載出來的!8痔埂究孕!
只不過參數(shù)格式不一樣,
普通類是“class 類名
匿名內(nèi)部類是“class 包名.外部類名$num





b.匿名內(nèi)部類的繼承結(jié)構(gòu)

  • 匿名內(nèi)部類被創(chuàng)建的時候爹凹,
    就默認(rèn) 匿名內(nèi)部類 是作為一個子類
    繼承其對應(yīng)的父類了:(接口亦同)

  • 但是下面這種類型厨诸,
    既 繼承某個父類 又 實現(xiàn)某個接口 的“匿名內(nèi)部類” 的 這種類型,
    在Java中是不被接受的禾酱,
    因為這其實是一種“或類型”微酬,
    即Runnable或上Foo的結(jié)果,作為一種類颤陶,
    這在Java中是不被接受的:

**即使使用Java 10 的var關(guān)鍵字來定義颗管,

  • 只能繼承一個父類或?qū)崿F(xiàn)一個接口
    >- 父類是非靜態(tài)的類型,則需父類外部實例來初始化
    >- 如果定義在非靜態(tài)作用域內(nèi)滓走,會引用外部類實例
    >- 只能捕獲外部作用域內(nèi)的final變量
    >- 創(chuàng)建時只有單一方法的接口可以用Lambda轉(zhuǎn)換




    ####a.匿名內(nèi)部類的名字
    表面上是沒有引用名的垦江,
    但其實是有用于定位的“名字”,
    如上代碼搅方,
    new Foo()在定義的時候比吭,
    重寫了bar()這個方法茬斧,
    如此一來new Foo(){...}這里就是一個匿名內(nèi)部類了;

    吶這個匿名內(nèi)部類梗逮,實際上在字節(jié)碼中是會定義出來的,P辶铩?锻!
    定義出來一個用于定位的“名字”怖喻,
    這個“名字”可見上面代碼的第二行底哗,
    com.bennyhuo.iiv.ch1.”即代碼包名
    OuterClass$1”即外部內(nèi)名$1锚沸,
    1代表這個匿名內(nèi)部類跋选,
    是前綴的外部類中,定義的第一個匿名內(nèi)部類哗蜈,
    再創(chuàng)建第二個匿名內(nèi)部類 就是$2了前标;

    所以匿名內(nèi)部類普通類一樣,是可以加載出來的>嗯恕A读小!
    只不過參數(shù)格式不一樣音比,
    普通類是“class 類名
    匿名內(nèi)部類是“class 包名.外部類名$num







    ####b.匿名內(nèi)部類的繼承結(jié)構(gòu)
    - 匿名內(nèi)部類被創(chuàng)建的時候俭尖,
    就默認(rèn) 匿名內(nèi)部類 是作為一個子類
    繼承其對應(yīng)的父類了:(接口亦同)


    - 但是下面這種類型,
    既 繼承某個父類 又 實現(xiàn)某個接口 的“匿名內(nèi)部類” 的 這種類型洞翩,
    在Java中是不被接受的稽犁,
    因為這其實是一種“或類型”,
    即Runnable或上Foo的結(jié)果骚亿,作為一種類已亥,
    這在Java中是不被接受的:

    >>
    即使使用Java 10 的var關(guān)鍵字來定義,
    也是不行的来屠,
    這種類型還是不能被接受:
    在處理 var時陷猫,編譯器先是查看表達(dá)式右邊部分,
    也就是所謂的構(gòu)造器的妖,并將它作為變量的類型绣檬,然后將該類型寫入字節(jié)碼當(dāng)中


    嗯,
    可是如果實在是想實現(xiàn)一個
    既 繼承某個父類 又 實現(xiàn)某個接口 的“匿名內(nèi)部類”這樣的類型嫂粟,
    但要不想占用太多資源娇未,要求同匿名內(nèi)部類一樣用完即銷毀,怎么辦星虹?
    那別用匿名內(nèi)部類唄零抬,
    方法體內(nèi)部實現(xiàn)即可镊讼,!F揭埂蝶棋!
    便可以在方法調(diào)用完畢后將其回收
    也可以達(dá)到需求

另外忽妒,Kotlin是可以實現(xiàn)玩裙,
既 繼承某個父類 又 實現(xiàn)某個接口 的“匿名內(nèi)部類” 的 這種類型的
(object類似于class與定義一個引用,
object與后面冒號之間不接名字表示匿名段直,
冒號后面要繼承什么吃溅,實現(xiàn)什么,直接寫出來就是了)





c.匿名內(nèi)部類的構(gòu)造方法(關(guān)注:匿名內(nèi)部類外部類引用

  • 匿名內(nèi)部類會有外部類的引用鸯檬,
    這個可能導(dǎo)致內(nèi)存泄漏决侈!

  • 匿名內(nèi)部類構(gòu)造方法編譯器 幫忙定義的!P瘛赖歌!
    開發(fā)者沒有權(quán) 定義匿名內(nèi)部類構(gòu)造方法

編譯器 會 根據(jù)代碼 為 匿名內(nèi)部類構(gòu)造方法 引入一些參數(shù)功茴,
如下面圖中例子俏站,
(右上)有一個OuterClass,里邊有一個InnerClass痊土,
(左上)這時候在Client類中肄扎,
new出來一個匿名內(nèi)部類

匿名內(nèi)部類——父類非靜態(tài)赁酝、所在方法(匿`類被new出來的位置所處的方法)非靜態(tài)

例子中這個new出來的匿名內(nèi)部類犯祠,
實際上它的父類就是InnerClass
而InnerClass本身是一個非靜態(tài)的內(nèi)部類酌呆,
:庠亍!O对L涤椤!非靜態(tài)的內(nèi)部類本身就會引用外部類的實例F惺铡@嬲觥!D榷F潞亍!
所以O(shè)uterClass()的實例也會在這里(左上第四行)new出來遍坟;

而下方的Client$1就是上述所說的匿名內(nèi)部類的類型了拳亿,
Client$1的命名格式其實就是剛剛說的外部內(nèi)名$匿名內(nèi)部類序號

所以圖中下方代碼塊的第二行愿伴,
編譯器 根據(jù)代碼 為 匿名內(nèi)部類生成的構(gòu)造方法肺魁,

第一個參數(shù),就是Client隔节,即匿名內(nèi)部類所在方法 對應(yīng)的 外部作用域(最外部類)鹅经;
因為這里的匿名內(nèi)部類所在的方法非靜態(tài)方法
所以一定是被某個實例(最外部類實例) 引用著的9倭薄!C烈辍9艉纭!

第二個參數(shù)呢诬,即匿名內(nèi)部類的父類涌哲,
這個父類如果是某外部類非靜態(tài)內(nèi)部類
那把這個對應(yīng)的外部類實例傳進(jìn)來即可尚镰,
因為這個外部類實例可以應(yīng)用到其成員(包括非靜態(tài)內(nèi)部類)阀圾;



匿名內(nèi)部類——父類靜態(tài)、所在方法非靜態(tài)

interface靜態(tài)內(nèi)部類的效果是差不多的狗唉,
就是靜態(tài)的初烘,
也就是不會去引用其外部類的實例!7指I隹稹!缸剪!
所以這時候匿名內(nèi)部類構(gòu)造方法的參數(shù)
就只有一個所在方法的最外部類實例了吗铐;



匿名內(nèi)部類--父類靜態(tài)、所在方法靜態(tài)

而杏节,當(dāng)匿名內(nèi)部類所在的方法是靜態(tài)的唬渗,
則其構(gòu)造方法的參數(shù)中,
不存在所在方法的最外部類實例了奋渔;

即镊逝,
匿名內(nèi)部類構(gòu)造方法參數(shù)個數(shù)
由其父類以及其所在方法 是否靜態(tài)決定嫉鲸,
父類非靜態(tài)蹋半,則需傳入父類相關(guān)實例
所在方法非靜態(tài),則需傳入所在方法的最外部類實例减江;
反則染突,
哪個靜態(tài)了,就不用傳哪個辈灼;
00 01 10 11



捕獲 匿名內(nèi)部類 所在方法內(nèi)(外部作用域) 的 局部變量快照的情況
匿名內(nèi)部類重寫父類方法時份企,引用到的外部方法體內(nèi)局部final變量

通常,要求要被捕獲的局部變量 需要是final修飾的巡莹;

雖然說如果不final的話司志,
匿名內(nèi)部類構(gòu)造方法也不是很有影響
因為傳給匿名內(nèi)部類構(gòu)造方法的這個局部變量實例降宅,
實際上只是捕獲局部變量實例的一個快照骂远,
快照即復(fù)制一份引用,給匿名內(nèi)部類構(gòu)造方法去使用腰根,

但是激才,
如果這個局部變量實例不是final的,
局部變量實例重新賦值了额嘿,
外部的局部變量實例跟傳給匿名內(nèi)部類構(gòu)造方法局部變量實例瘸恼,就不一樣了!
這個肯定是不行的吧册养,

所以东帅,
Java要求,
這個地方(圖中左邊球拦,第三行靠闭,也即被傳給 匿' 構(gòu)造方法 的這個 局部實例一定要是final的,
原因就是為了讓這個局部變量實例坎炼,在外部和在 匿’ 構(gòu)造方法 中阎毅,
保持一致

匿名內(nèi)部類的構(gòu)造方法小結(jié)

  • 是編譯器生成的

  • 參數(shù)列表包括

    • 外部對象(定義在非靜態(tài)域內(nèi))<如上的Client>

    • 父類的外部對象(父類非靜態(tài))<如上的OuterClass>

    • 父類的構(gòu)造方法參數(shù)(父類有構(gòu)造方法且參數(shù)列表不為空)

    • 外部捕獲的變量(方法體內(nèi)有引用外部final變量)<如上的Object>

  • 事實上是可以通過反射点弯,
    去修改匿名內(nèi)部類構(gòu)造方法持有的外部引用參數(shù)列表)的



Lambda轉(zhuǎn)換(SAM轉(zhuǎn)換)

  • SAM--single abstract method 單一方法類型

一個接口扇调,只有一個抽象方法時,可以用Lambda表達(dá)式替換實現(xiàn)抢肛;

關(guān)注語言版本的變化

  • 體現(xiàn)對技術(shù)的熱情
  • 體現(xiàn)好學(xué)的品質(zhì)
  • 顯得專業(yè)





最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末狼钮,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子捡絮,更是在濱河造成了極大的恐慌熬芜,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件福稳,死亡現(xiàn)場離奇詭異涎拉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門鼓拧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來半火,“玉大人,你說我怎么就攤上這事季俩∨ヌ牵” “怎么了?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵酌住,是天一觀的道長店归。 經(jīng)常有香客問我,道長酪我,這世上最難降的妖魔是什么消痛? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮都哭,結(jié)果婚禮上秩伞,老公的妹妹穿的比我還像新娘。我一直安慰自己质涛,他們只是感情好稠歉,可當(dāng)我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布掰担。 她就那樣靜靜地躺著汇陆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪带饱。 梳的紋絲不亂的頭發(fā)上毡代,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天,我揣著相機(jī)與錄音勺疼,去河邊找鬼教寂。 笑死,一個胖子當(dāng)著我的面吹牛执庐,可吹牛的內(nèi)容都是我干的酪耕。 我是一名探鬼主播,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼轨淌,長吁一口氣:“原來是場噩夢啊……” “哼迂烁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起递鹉,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤盟步,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后躏结,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體却盘,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了黄橘。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兆览。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖旬陡,靈堂內(nèi)的尸體忽然破棺而出拓颓,到底是詐尸還是另有隱情,我是刑警寧澤描孟,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布驶睦,位于F島的核電站,受9級特大地震影響匿醒,放射性物質(zhì)發(fā)生泄漏场航。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一廉羔、第九天 我趴在偏房一處隱蔽的房頂上張望溉痢。 院中可真熱鬧,春花似錦憋他、人聲如沸孩饼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽镀娶。三九已至,卻和暖如春揪罕,著一層夾襖步出監(jiān)牢的瞬間梯码,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工好啰, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留轩娶,地道東北人。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓框往,卻偏偏與公主長得像鳄抒,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子椰弊,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容