內(nèi)部類

成員內(nèi)部類

成員內(nèi)部類可以無條件訪問外部類的所有成員屬性和成員方法(包括private成員和靜態(tài)成員)。

不過要注意的是士鸥,當成員內(nèi)部類擁有和外部類同名的成員變量或者方法時灼伤,會發(fā)生隱藏現(xiàn)象搏色,即默認情況下訪問的是成員內(nèi)部類的成員仰猖。如果要訪問外部類的同名成員,需要以下面的形式進行訪問:外部類.this.成員變量神得、外部類.this.成員方法沽损。

雖然成員內(nèi)部類可以無條件地訪問外部類的成員,而外部類想訪問成員內(nèi)部類的成員卻不是這么隨心所欲了循头。在外部類中如果要訪問成員內(nèi)部類的成員绵估,必須先創(chuàng)建一個成員內(nèi)部類的對象,再通過指向這個對象的引用來訪問卡骂。

成員內(nèi)部類是依附外部類而存在的国裳,也就是說,如果要創(chuàng)建成員內(nèi)部類的對象全跨,前提是必須存在一個外部類的對象缝左。創(chuàng)建成員內(nèi)部類對象的一般方式如下:

//第一種方式:

Outter outter =?new?Outter();

Outter.Inner inner = outter.new?Inner();?//必須通過Outter對象來創(chuàng)建

//第二種方式:

Outter.Inner inner1 = outter.getInnerInstance();

public Inner getInnerInstance() { if(inner == null) {inner = new Inner(); }return inner; }

內(nèi)部類可以擁有private訪問權(quán)限、protected訪問權(quán)限、public訪問權(quán)限及包訪問權(quán)限渺杉。如果成員內(nèi)部類Inner用private修飾蛇数,則只能在外部類的內(nèi)部訪問,如果用public修飾是越,則任何地方都能訪問耳舅;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問倚评;如果是默認訪問權(quán)限浦徊,則只能在同一個包下訪問。這一點和外部類有一點不一樣天梧,外部類只能被public和包訪問兩種權(quán)限修飾盔性。我個人是這么理解的,由于成員內(nèi)部類看起來像是外部類的一個成員呢岗,所以可以像類的成員一樣擁有多種權(quán)限修飾冕香。



局部內(nèi)部類

局部內(nèi)部類是定義在一個方法或者一個作用域里面的類,它和成員內(nèi)部類的區(qū)別在于局部內(nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)后豫。

局部內(nèi)部類就像是方法里面的一個局部變量一樣悉尾,是不能有public、protected硬贯、private以及static修飾符的。



匿名內(nèi)部類

匿名內(nèi)部類是唯一一種沒有構(gòu)造器的類陨收。正因為其沒有構(gòu)造器饭豹,所以匿名內(nèi)部類的使用范圍非常有限,大部分匿名內(nèi)部類用于接口回調(diào)务漩。匿名內(nèi)部類在編譯的時候由系統(tǒng)自動起名為Outter$1.class拄衰。一般來說,匿名內(nèi)部類用于繼承其他類或是實現(xiàn)接口饵骨,并不需要增加額外的方法翘悉,只是對繼承方法的實現(xiàn)或是重寫。



靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類也是定義在另一個類里面的類居触,只不過在類的前面多了一個關(guān)鍵字static妖混。靜態(tài)內(nèi)部類是不需要依賴于外部類的,這點和類的靜態(tài)成員屬性有點類似轮洋,并且它不能使用外部類的非static成員變量或者方法,這點很好理解,因為在沒有外部類的對象的情況下问芬,可以創(chuàng)建靜態(tài)內(nèi)部類的對象楼肪,如果允許訪問外部類的非static成員就會產(chǎn)生矛盾,因為外部類的非static成員必須依附于具體的對象。

?Outter.Inner inner =?new?Outter.Inner();



深入理解內(nèi)部類

1.為什么成員內(nèi)部類可以無條件訪問外部類的成員误褪?

Outter.java


編譯之后责鳍,出現(xiàn)了兩個字節(jié)碼文件

反編譯Outter$Inner.class里有一句:finalcom.cxh.test2.Outterthis$0;

這行是一個指向外部類對象的指針。也就是說編譯器會默認為成員內(nèi)部類添加了一個指向外部類對象的引用兽间,那么這個引用是如何賦初值的呢历葛?下面接著看內(nèi)部類的構(gòu)造器:publiccom.cxh.test2.Outter$Inner(com.cxh.test2.Outter);

從這里可以看出,雖然我們在定義的內(nèi)部類的構(gòu)造器是無參構(gòu)造器渡八,編譯器還是會默認添加一個參數(shù)啃洋,該參數(shù)的類型為指向外部類對象的一個引用,所以成員內(nèi)部類中的Outter this&0 指針便指向了外部類對象屎鳍,因此可以在成員內(nèi)部類中隨意訪問外部類的成員宏娄。從這里也間接說明了成員內(nèi)部類是依賴于外部類的,如果沒有創(chuàng)建外部類的對象逮壁,則無法對Outter this&0引用進行初始化賦值孵坚,也就無法創(chuàng)建成員內(nèi)部類的對象了。


2.為什么局部內(nèi)部類和匿名內(nèi)部類只能訪問局部final變量窥淆?

示例一:

局部內(nèi)部類

這段代碼會被編譯成兩個class文件:Test.class和Test1.class卖宠。默認情況下,編譯器會為匿名內(nèi)部類和局部內(nèi)部類起名為Outter1.class忧饭。默認情況下扛伍,編譯器會為匿名內(nèi)部類和局部內(nèi)部類起名為Outterx.class(x為正整數(shù))。

反編譯的 run方法

上段代碼中词裤,如果把變量a和b前面的任一個final去掉刺洒,這段代碼都編譯不過。我們先考慮這樣一個問題:當test方法執(zhí)行完畢之后吼砂,變量a的生命周期就結(jié)束了逆航,而此時Thread對象的生命周期很可能還沒有結(jié)束,那么在Thread的run方法中繼續(xù)訪問變量a就變成不可能了渔肩,但是又要實現(xiàn)這樣的效果因俐,怎么辦呢?Java采用了?復制的手段來解決這個問題周偎。將這段代碼的字節(jié)碼反編譯可以得到下面的內(nèi)容抹剩,在run方法中有一條指令:bipush 10。

這條指令表示將操作數(shù)10壓棧蓉坎,表示使用的是一個本地局部變量吧兔。這個過程是在編譯期間由編譯器默認進行,如果這個變量的值在編譯期間可以確定袍嬉,則編譯器默認會在匿名內(nèi)部類(局部內(nèi)部類)的常量池中添加一個內(nèi)容相等的字面量或直接將相應(yīng)的字節(jié)碼嵌入到執(zhí)行字節(jié)碼中境蔼。這樣一來灶平,匿名內(nèi)部類使用的變量是另一個局部變量,只不過值和方法中局部變量的值相等箍土,因此和方法中的局部變量完全獨立開逢享。


示例二:

局部內(nèi)部類2
反編譯得到的構(gòu)造方法

我們看到匿名內(nèi)部類Test$1的構(gòu)造器含有兩個參數(shù),一個是指向外部類對象的引用吴藻,一個是int型變量瞒爬,很顯然,這里是將變量test方法中的形參a以參數(shù)的形式傳進來對匿名內(nèi)部類中的拷貝(變量a的拷貝)進行賦值初始化沟堡。

也就說如果局部變量的值在編譯期間就可以確定侧但,則直接在匿名內(nèi)部里面創(chuàng)建一個拷貝。如果局部變量的值無法在編譯期間確定航罗,則通過構(gòu)造器傳參的方式來對拷貝進行初始化賦值禀横。

在run方法中訪問的變量a根本就不是test方法中的局部變量a。這樣一來就解決了前面所說的 生命周期不一致的問題粥血。但是新的問題又來了柏锄,既然在run方法中訪問的變量a和test方法中的變量a不是同一個變量,當在run方法中改變變量a的值的話复亏,會出現(xiàn)什么情況趾娃?會造成數(shù)據(jù)不一致性,這樣就達不到原本的意圖和要求缔御。為了解決這個問題抬闷,java編譯器就限定必須將變量a限制為final變量,不允許對變量a進行更改(對于引用類型的變量耕突,是不允許指向新的對象)笤成,這樣數(shù)據(jù)不一致性的問題就得以解決了。


3.靜態(tài)內(nèi)部類有特殊的地方嗎有勾?

靜態(tài)內(nèi)部類是不依賴于外部類的疹启,也就說可以在不創(chuàng)建外部類對象的情況下創(chuàng)建內(nèi)部類的對象古程。另外蔼卡,靜態(tài)內(nèi)部類是不持有指向外部類對象的引用的。



內(nèi)部類的使用場景和好處

1.每個內(nèi)部類都能獨立的繼承一個接口的實現(xiàn)挣磨,所以無論外部類是否已經(jīng)繼承了某個(接口的)實現(xiàn)雇逞,對于內(nèi)部類都沒有影響。內(nèi)部類使得多繼承的解決方案變得完整茁裙。

2.方便將存在一定邏輯關(guān)系的類組織在一起塘砸,又可以對外界隱藏。

3.方便編寫事件驅(qū)動程序晤锥。

4.方便編寫線程代碼掉蔬。


參考:Java內(nèi)部類詳解

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末廊宪,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子女轿,更是在濱河造成了極大的恐慌箭启,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,372評論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蛉迹,死亡現(xiàn)場離奇詭異傅寡,居然都是意外死亡,警方通過查閱死者的電腦和手機北救,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評論 3 392
  • 文/潘曉璐 我一進店門荐操,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人珍策,你說我怎么就攤上這事托启。” “怎么了膛壹?”我有些...
    開封第一講書人閱讀 162,415評論 0 353
  • 文/不壞的土叔 我叫張陵驾中,是天一觀的道長。 經(jīng)常有香客問我模聋,道長肩民,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,157評論 1 292
  • 正文 為了忘掉前任链方,我火速辦了婚禮持痰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘祟蚀。我一直安慰自己工窍,他們只是感情好,可當我...
    茶點故事閱讀 67,171評論 6 388
  • 文/花漫 我一把揭開白布前酿。 她就那樣靜靜地躺著患雏,像睡著了一般。 火紅的嫁衣襯著肌膚如雪罢维。 梳的紋絲不亂的頭發(fā)上淹仑,一...
    開封第一講書人閱讀 51,125評論 1 297
  • 那天,我揣著相機與錄音肺孵,去河邊找鬼匀借。 笑死,一個胖子當著我的面吹牛平窘,可吹牛的內(nèi)容都是我干的吓肋。 我是一名探鬼主播,決...
    沈念sama閱讀 40,028評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼瑰艘,長吁一口氣:“原來是場噩夢啊……” “哼是鬼!你這毒婦竟也來了肤舞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,887評論 0 274
  • 序言:老撾萬榮一對情侶失蹤均蜜,失蹤者是張志新(化名)和其女友劉穎萨赁,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體兆龙,經(jīng)...
    沈念sama閱讀 45,310評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡杖爽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,533評論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了紫皇。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片慰安。...
    茶點故事閱讀 39,690評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖聪铺,靈堂內(nèi)的尸體忽然破棺而出化焕,到底是詐尸還是另有隱情,我是刑警寧澤铃剔,帶...
    沈念sama閱讀 35,411評論 5 343
  • 正文 年R本政府宣布撒桨,位于F島的核電站,受9級特大地震影響键兜,放射性物質(zhì)發(fā)生泄漏凤类。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,004評論 3 325
  • 文/蒙蒙 一普气、第九天 我趴在偏房一處隱蔽的房頂上張望谜疤。 院中可真熱鬧,春花似錦现诀、人聲如沸夷磕。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坐桩。三九已至,卻和暖如春封锉,著一層夾襖步出監(jiān)牢的瞬間绵跷,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,812評論 1 268
  • 我被黑心中介騙來泰國打工烘浦, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留抖坪,地道東北人萍鲸。 一個月前我還...
    沈念sama閱讀 47,693評論 2 368
  • 正文 我出身青樓闷叉,卻偏偏與公主長得像,于是被迫代替她去往敵國和親脊阴。 傳聞我的和親對象是個殘疾皇子握侧,可洞房花燭夜當晚...
    茶點故事閱讀 44,577評論 2 353

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