Thinking in java筆記:《第十章: 內(nèi)部類》

可以將一個(gè)類的定義放到另一個(gè)類的定義內(nèi)部,這就是內(nèi)部類。

10.1 創(chuàng)建內(nèi)部類

如果想從外部類的非靜態(tài)方法之外的任意位置創(chuàng)建某個(gè)內(nèi)部類的對(duì)象,那么必須具體指明這個(gè)對(duì)象的類型:OuterClassname.InnerClassName

10.2 鏈接到外部類

當(dāng)生成一個(gè)內(nèi)部類的對(duì)象時(shí),此對(duì)象與制造它的外圍對(duì)象之間就有了一種關(guān)系,所以他能訪問其外圍對(duì)象的所有成員,而不需要任何特殊條件。此外,內(nèi)部類還擁有其外圍類的所有元素的訪問權(quán)。
當(dāng)某個(gè)外圍類的對(duì)象創(chuàng)建一個(gè)內(nèi)部類對(duì)象時(shí),次內(nèi)部類對(duì)象必定會(huì)秘密地捕獲一個(gè)指向那個(gè)外圍類對(duì)象的引用(內(nèi)部類是非static類時(shí))。

10.3 使用.this 和 .new

如果你需要生成對(duì)外部類對(duì)象的引用,可以使用外部類的名字后面緊跟圓點(diǎn)和this:OuterClassName.this
要想直接創(chuàng)建內(nèi)部類的對(duì)象,你不能按照你想象的方式,去引用外部類的名字,而是必須使用外部類的對(duì)象來創(chuàng)建該內(nèi)部類的對(duì)象。

在擁有外部類對(duì)象之前是不可能創(chuàng)建內(nèi)部類對(duì)象的。
一個(gè)內(nèi)部類被嵌套多少層并不重要,它能透明地訪問所有它所嵌入的外圍類的所有成員。

10.4 內(nèi)部類和向上轉(zhuǎn)型

當(dāng)內(nèi)部類向上轉(zhuǎn)型為其基類,尤其是轉(zhuǎn)型為一個(gè)接口的時(shí)候,內(nèi)部類有了特殊的作用。內(nèi)部類關(guān)于某個(gè)接口的實(shí)現(xiàn)能夠完全不可見,并且不可用。我們只能得到指向基類或者接口的引用,所以能夠很方便地隱藏實(shí)現(xiàn)細(xì)節(jié)。

10.5 在方法和作用域內(nèi)的內(nèi)部類

又名局部內(nèi)部類
使用場景:

  1. 你實(shí)現(xiàn)了某類型的接口,于是可以創(chuàng)建并返回對(duì)其的引用
  2. 你要解決一個(gè)復(fù)雜的問題,想創(chuàng)建一個(gè)雷來輔助你的解決方案,但是又不希望這個(gè)雷士公共可用的。

10.6 匿名內(nèi)部類

看起來似乎是你正要返回一個(gè)對(duì)象。但是然后(在到達(dá)預(yù)付結(jié)束的分號(hào)之前)你卻說:“等一等,我想在這里插入一個(gè)類的定義”。即:定義并立即返回一個(gè)類的實(shí)例。

  • 可以使用實(shí)例初始化達(dá)到匿名內(nèi)部類的構(gòu)造器的效果。但是不能重載實(shí)力初始化方法,所以你僅有一個(gè)這樣的構(gòu)造器。
  • 匿名內(nèi)部類既可以擴(kuò)展類,又可以實(shí)現(xiàn)接口,但是不能兩者兼?zhèn)洹6覍?shí)現(xiàn)接口,也只能實(shí)現(xiàn)一個(gè)接口。

如果定義一個(gè)匿名內(nèi)部類,并且希望它使用一個(gè)在其外部定義的對(duì)象,那么編譯器要求其參數(shù)引用是final的。

10.7 嵌套類 static

  1. 要?jiǎng)?chuàng)建嵌套類的對(duì)象,并不需要其外圍類的對(duì)象
  2. 不能從嵌套類的對(duì)象中訪問非靜態(tài)的外圍類的對(duì)象。

10.7.1 接口內(nèi)部的類

如果你想要?jiǎng)?chuàng)建某些公用代碼,使得他們可以被某個(gè)接口的所有不同實(shí)現(xiàn)所公用,那么使用接口內(nèi)部的嵌套類會(huì)顯得很方便。

10.8 為什么需要內(nèi)部類

每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)內(nèi)部類都沒有影響。
如果沒有內(nèi)部類提供的、可以繼承多個(gè)具體的或抽象的類的能力,一些設(shè)計(jì)與編程問題就很難解決。
如果不需要解決“多重繼承”的問題,那么自然可以用別的方式編碼,而不需要使用內(nèi)部類。但如果使用內(nèi)部類,還可以獲得其他一些特性:

  1. 內(nèi)部類可以有多個(gè)實(shí)例,每個(gè)實(shí)例都有自己的狀態(tài)信息,并且與其外圍類對(duì)象的信息相互獨(dú)立
  2. 在單個(gè)外圍類中,可以讓多個(gè)內(nèi)部類以不同的方式實(shí)現(xiàn)同一個(gè)接口,或繼承同一個(gè)類。
  3. 創(chuàng)建內(nèi)部類對(duì)象的時(shí)刻并不依賴于外圍類對(duì)象的創(chuàng)建。
  4. 內(nèi)部類沒有令人迷糊的"is-a"關(guān)系,他就是一個(gè)獨(dú)立地實(shí)體。

10.8.1閉包與回調(diào)

內(nèi)部類是面向?qū)ο蟮拈]包。

interface Incrementable{
    void increment();
}

class MyIncrement{
    public void increment(){
        System.out.println("Other operation");
    }
    public static void f(MyIncrement mi){
        mi.increment();
    }
}

class Callee1 implements Incrementable{

    private  int i=0;
    @Override
    public void increment() {
        i++;
        System.out.println(i);
    }
}
class Callee2 extends MyIncrement{
    private int i=0;

    @Override
    public void increment() {
        super.increment();
        i++;
        System.out.println(i);
    }
    private class Closure implements Incrementable{
        @Override
        public void increment() {
            Callee2.this.increment();
            System.out.println("Closure increment");
        }
    }
    Incrementable getCallbackReference(){
        return new Closure();
    }
}

class Caller{
    private Incrementable callbackRefrence;
    Caller(Incrementable cbh){
        callbackRefrence=cbh;
    }
    void go(){
        callbackRefrence.increment();
    }
}

public class Callbacks {
    public static void main(String[] args){
        Callee1 c1=new Callee1();
        Callee2 c2=new Callee2();
        MyIncrement.f(c2);
        Caller caller1=new Caller(c1);
        Caller caller2=new Caller(c2.getCallbackReference());
        caller1.go();
        caller1.go();
        caller2.go();
        caller2.go();
    }

}

Callee1是簡單地解決方式.Callee2繼承自MyIncrement,已經(jīng)有一個(gè)不同的increment()方法,與Incrementable沖突且完全不想關(guān)。所以不能為了Incrementable的用途而覆蓋inrement()方法,于是只能使用內(nèi)部類獨(dú)立地實(shí)現(xiàn)Inrementable。

在Callee2中除了getCallbackReference()以外,其他成員都是private的。只能通過interface Incrementable接口。這是一個(gè)安全的鉤子(hook),無論誰獲得Incrementable的引用,都只能調(diào)用increment()方法。

10.8.2 內(nèi)部類與控制框架

在控制框架中使用內(nèi)部類 ,可以:

  1. 控制框架的完整實(shí)現(xiàn)是由單個(gè)的類創(chuàng)建的,從而使得實(shí)現(xiàn)的細(xì)節(jié)被封裝起來。內(nèi)部類用來表示解決問題所需的各種不同的action()。
  2. 內(nèi)部類能夠很容易地訪問外圍類的任意成員,避免實(shí)現(xiàn)變得笨拙。

10.9 內(nèi)部類的繼承

語法:
enclosingClassReference.super();

class WithInner{
    class Inner{}
}
public class InheritInner extends WithInner.Inner{
    public InheritInner(WithInner wi) {
        wi.super();
    }
    public static void main(String[] args){
        WithInner inner=new WithInner();
        InheritInner ii=new InheritInner(inner);
    }
}

10.10 內(nèi)部類可以被覆蓋嗎?

當(dāng)繼承了某個(gè)外圍類的時(shí)候,內(nèi)部類并沒有發(fā)生什么神奇的變化。這兩個(gè)內(nèi)部類是完全獨(dú)立的兩個(gè)實(shí)體,各自在自己的命名空間內(nèi)。

10.11 局部內(nèi)部類

可以在代碼塊里創(chuàng)建內(nèi)部類,典型的方式是在一個(gè)方法體的里面創(chuàng)建。局部內(nèi)部類不能有訪問說明符,因?yàn)樗皇峭鈬惖囊徊糠郑坏撬梢栽L問當(dāng)前代碼塊內(nèi)的常量,以及此外圍類的所有成員。

使用局部內(nèi)部類而不是匿名內(nèi)部類的理由:

  1. 我們需要一個(gè)已命名的構(gòu)造器,或者需要重載構(gòu)造器,而匿名內(nèi)部類只能用于實(shí)力初始化。
  2. 需要不止一個(gè)該內(nèi)部類的對(duì)象。

10.12 內(nèi)部類標(biāo)識(shí)符

內(nèi)部類類文件的命名有嚴(yán)格的規(guī)則:外圍類的名字,加上"$",再加上內(nèi)部類的名字。
如果內(nèi)部類是匿名的,編譯器會(huì)簡單地產(chǎn)生一個(gè)數(shù)字作為其標(biāo)識(shí)符。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,565評(píng)論 6 539
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,115評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,577評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,514評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,234評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,621評(píng)論 1 326
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,641評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,822評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,380評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,128評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,319評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,879評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,548評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,970評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,229評(píng)論 1 291
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,048評(píng)論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,285評(píng)論 2 376

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

  • 1.本章上來第一句就說了什么是內(nèi)部類,一個(gè)在類的定義放在另一個(gè)的類內(nèi)部。 2.內(nèi)部類擁有外部類其外圍類的所有元素的...
    Gzw丶南山閱讀 180評(píng)論 0 0
  • 內(nèi)部類是一種非常有用的特性,因?yàn)樗试S你把一些邏輯相關(guān)的類組織在一起,并控制位于內(nèi)部的類的可視性。 如果想從外部類...
    Lemon_Home閱讀 225評(píng)論 0 0
  • 今天整理一下內(nèi)部類,其中包含了內(nèi)部類的特殊形式,對(duì)比普通類有什么區(qū)別和作用,內(nèi)部類和外圍類之間的聯(lián)系,內(nèi)部類的擴(kuò)展...
    _小二_閱讀 631評(píng)論 0 3
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法,內(nèi)部類的語法,繼承相關(guān)的語法,異常的語法,線程的語...
    子非魚_t_閱讀 31,731評(píng)論 18 399
  • 月夜色正好,幽靜又寂寥。 微風(fēng)不喧鬧,蟲兒也悄悄。 唯有霓虹場,壞了夜幕殤。 夜深無處去?迷途心仿徨。
    序小木閱讀 262評(píng)論 37 19