什么是內(nèi)部類(lèi)
個(gè)類(lèi)放在另一個(gè)類(lèi)的內(nèi)部,稱(chēng)之為內(nèi)部類(lèi)
為什么要放到別的類(lèi)內(nèi)部呢溜哮?
內(nèi)部類(lèi)與包含它的外部類(lèi)有比較密切的關(guān)系悠栓,而與其他類(lèi)關(guān)系不大,定義在類(lèi)內(nèi)部惫周,可以實(shí)現(xiàn)對(duì)外部完全隱藏尘惧,可以有更好的封裝性,代碼實(shí)現(xiàn)上也往往更為簡(jiǎn)潔递递。
注意點(diǎn)
對(duì)于Java虛擬機(jī)而言喷橙,它是不知道內(nèi)部類(lèi)這回事的, 每個(gè)內(nèi)部類(lèi)最后都會(huì)被編譯為一個(gè)獨(dú)立的類(lèi)啥么,生成一個(gè)獨(dú)立的字節(jié)碼文件
根據(jù)定義的位置和方式不同,分四種
靜態(tài)內(nèi)部類(lèi)
-
語(yǔ)法
靜態(tài)內(nèi)部類(lèi)與靜態(tài)變量和靜態(tài)方法定義的位置一樣贰逾,也帶有static關(guān)鍵字悬荣,只是它定義的是類(lèi)
image.png
可以訪問(wèn)外部類(lèi)的靜態(tài)變量和方法, 不可以訪問(wèn)實(shí)例變量和方法疙剑。 在類(lèi)內(nèi)部氯迂,可以直接使用內(nèi)部靜態(tài)類(lèi)
public靜態(tài)內(nèi)部類(lèi)可以被外部使用, 需要通過(guò)"外部類(lèi).靜態(tài)內(nèi)部類(lèi)"的方式使用
- 實(shí)現(xiàn)原理
以上代碼實(shí)際上會(huì)生成兩個(gè)類(lèi)核芽,一個(gè)是Outer囚戚,另一個(gè)是Outer$StaticInner
image.png
內(nèi)部類(lèi)訪問(wèn)了外部類(lèi)的一個(gè)私有靜態(tài)變量shared酵熙, 而我們知道私有變量是不能被類(lèi)外部訪問(wèn)的轧简, Java的解決方法是,自動(dòng)為Outer生成了一個(gè)非私有訪問(wèn)方法access$0匾二, 它返回這個(gè)私有靜態(tài)變量shared哮独。
- 使用場(chǎng)景
如果它與外部類(lèi)關(guān)系密切,且不依賴(lài)于外部類(lèi)實(shí)例察藐,則可以考慮定義為靜態(tài)內(nèi)部類(lèi)
LinkedList類(lèi)內(nèi)部有一個(gè)私有靜態(tài)內(nèi)部類(lèi)Node
成員內(nèi)部類(lèi)
- 語(yǔ)法
成員內(nèi)部類(lèi)沒(méi)有static修飾符
image.png
與靜態(tài)內(nèi)部類(lèi)不同皮璧,除了靜態(tài)變量和方法, 成員內(nèi)部類(lèi)還可以直接訪問(wèn)外部類(lèi)的實(shí)例變量和方法
在外部類(lèi)內(nèi)分飞,使用成員內(nèi)部類(lèi)與靜態(tài)內(nèi)部類(lèi)是一樣的悴务, 直接使用即可,如test()方法所示譬猫。與靜態(tài)內(nèi)部類(lèi)不同讯檐, 成員內(nèi)部類(lèi)對(duì)象總是與一個(gè)外部類(lèi)對(duì)象相連的, 在外部使用時(shí)染服,它不能直接通過(guò)new Outer.Inner()的方式創(chuàng)建對(duì)象别洪, 而是要先將創(chuàng)建一個(gè)Outer類(lèi)對(duì)象
與靜態(tài)內(nèi)部類(lèi)不同,成員內(nèi)部類(lèi)中不可以定義靜態(tài)變量和方法 (final變量例外柳刮,它等同于常量)挖垛, 下面介紹的方法內(nèi)部類(lèi)和匿名內(nèi)部類(lèi)也都不可以
- 實(shí)現(xiàn)原理
以上代碼也會(huì)生成兩個(gè)類(lèi),一個(gè)是Outer秉颗,另一個(gè)是Outer$Inner
image.png
image.png
Outer$Inner類(lèi)有個(gè)實(shí)例變量outer指向外部類(lèi)的對(duì)象痢毒, 它在構(gòu)造方法中被初始化,Outer在新建Outer$Inner對(duì)象時(shí)傳遞當(dāng)前對(duì)象給它蚕甥, 由于內(nèi)部類(lèi)訪問(wèn)了外部類(lèi)的私有變量和方法哪替, 外部類(lèi)Outer生成了兩個(gè)非私有靜態(tài)方法,access$0用于訪問(wèn)變量a梢灭,access$1用于訪問(wèn)方法action夷家。
- 使用場(chǎng)景
如果內(nèi)部類(lèi)與外部類(lèi)關(guān)系密切蒸其,且操作或依賴(lài)外部類(lèi)實(shí)例變量和方法,則可以考慮定義為成員內(nèi)部類(lèi)库快。
外部類(lèi)的一些方法的返回值可能是某個(gè)接口摸袁,為了返回這個(gè)接口,外部類(lèi)方法可能使用內(nèi)部類(lèi)實(shí)現(xiàn)這個(gè)接口义屏,這個(gè)內(nèi)部類(lèi)可以被設(shè)為private靠汁,對(duì)外完全隱藏。
LinkedList中闽铐,它的兩個(gè)方法listIterator和descendingIterator的返回值都是接口Iterator蝶怔, 調(diào)用者可以通過(guò)Iterator接口對(duì)鏈表遍歷,listIterator和descendingIterator內(nèi)部分別使用了成員內(nèi)部類(lèi)ListItr和DescendingIterator兄墅,這兩個(gè)內(nèi)部類(lèi)都實(shí)現(xiàn)了接口Iterator
方法內(nèi)部類(lèi)
-
語(yǔ)法
內(nèi)部類(lèi)還可以定義在一個(gè)方法體中
image.png
類(lèi)Inner定義在外部類(lèi)方法test中踢星,方法內(nèi)部類(lèi)只能在定義的方法內(nèi)被使用。 如果方法是實(shí)例方法隙咸,則除了靜態(tài)變量和方法沐悦,內(nèi)部類(lèi)還可以直接訪問(wèn)外部類(lèi)的實(shí)例變量和方法,如innerMethod直接訪問(wèn)了外部私有實(shí)例變量a五督。如果方法是靜態(tài)方法藏否,則方法內(nèi)部類(lèi)只能訪問(wèn)外部類(lèi)的靜態(tài)變量和方法。
方法內(nèi)部類(lèi)還可以直接訪問(wèn)方法的參數(shù)和方法中的局部變量充包,不過(guò)副签, 這些變量必須被聲明為final,如innerMethod直接訪問(wèn)了方法參數(shù)param和局部變量str基矮。
-
實(shí)現(xiàn)原理
image.png
image.png
方法內(nèi)部類(lèi)可以訪問(wèn)方法中的參數(shù)和局部變量淆储,這是通過(guò)在構(gòu)造方法中傳遞參數(shù)來(lái)實(shí)現(xiàn)的
方法內(nèi)部類(lèi)操作的并不是外部的變量,而是它自己的實(shí)例變量愈捅,只是這些變量的值和外部一樣遏考, 對(duì)這些變量賦值,并不會(huì)改變外部的值蓝谨,為避免混淆灌具,所以干脆強(qiáng)制規(guī)定必須聲明為final。
如果的確需要修改外部的變量譬巫,可以將變量改為只含該變量的數(shù)組
- 使用場(chǎng)景
方法內(nèi)部類(lèi)都可以用成員內(nèi)部類(lèi)代替咖楣,至于方法參數(shù),也可以作為參數(shù)傳遞給成員內(nèi)部類(lèi)芦昔。 不過(guò)诱贿,如果類(lèi)只在某個(gè)方法內(nèi)被使用,使用方法內(nèi)部類(lèi),可以實(shí)現(xiàn)更好的封裝珠十。
匿名內(nèi)部類(lèi)
-
語(yǔ)法
匿名內(nèi)部類(lèi)沒(méi)有名字料扰,在創(chuàng)建對(duì)象的同時(shí)定義類(lèi)
image.pngimage.png
匿名內(nèi)部類(lèi)只能被使用一次,用來(lái)創(chuàng)建一個(gè)對(duì)象焙蹭。它沒(méi)有名字晒杈,沒(méi)有構(gòu)造方法
因?yàn)闆](méi)有構(gòu)造方法,它自己無(wú)法接受參數(shù)孔厉,如果必須要參數(shù)拯钻,則應(yīng)該使用其他內(nèi)部類(lèi)。
與方法內(nèi)部類(lèi)一樣撰豺,匿名內(nèi)部類(lèi)也可以訪問(wèn)外部類(lèi)的所有變量和方法粪般,可以訪問(wèn)方法中的final參數(shù)和局部變量。
-
實(shí)現(xiàn)原理
每個(gè)匿名內(nèi)部類(lèi)也都被生成為了一個(gè)獨(dú)立的類(lèi)污桦,只是類(lèi)的名字以外部類(lèi)加數(shù)字編號(hào)亩歹,沒(méi)有有意義的名字。
image.png
image.png
與方法內(nèi)部類(lèi)類(lèi)似寡润,外部實(shí)例this捆憎,方法參數(shù)x和y都作為參數(shù)傳遞給了內(nèi)部類(lèi)構(gòu)造方法舅柜。 此外梭纹,new時(shí)的參數(shù)2和3也傳遞給了構(gòu)造方法,內(nèi)部類(lèi)構(gòu)造方法又將它們傳遞給了父類(lèi)構(gòu)造方法致份。
-
使用場(chǎng)景
匿名內(nèi)部類(lèi)能做的变抽,方法內(nèi)部類(lèi)都能做。但如果對(duì)象只會(huì)創(chuàng)建一次氮块,且不需要構(gòu)造方法來(lái)接受參數(shù)绍载,則可以使用匿名內(nèi)部類(lèi),代碼書(shū)寫(xiě)上更為簡(jiǎn)潔滔蝉。
匿名內(nèi)部類(lèi)還經(jīng)常用于事件處理程序中击儡,用于響應(yīng)某個(gè)事件,比如說(shuō)一個(gè)Button蝠引,處理點(diǎn)擊事件的代碼可能類(lèi)似如下:
image.png
將程序分為保持不變的主體框架阳谍,和針對(duì)具體情況的可變邏輯, 通過(guò)回調(diào)的方式進(jìn)行協(xié)作螃概,是計(jì)算機(jī)程序的一種常用實(shí)踐矫夯。匿名內(nèi)部類(lèi)是實(shí)現(xiàn)回調(diào)接口的一種簡(jiǎn)便方式。