Java內(nèi)部類機(jī)制詳解

Java允許在一個(gè)類里面定義另一個(gè)類欢策,類里面的類就是內(nèi)部類。內(nèi)部類看似簡單关串,其實(shí)里面大有乾坤拧廊,下面我們就來好好聊一聊內(nèi)部類。代碼示例在最下面晋修。

初識(shí)內(nèi)部類

內(nèi)部類作用及其一些共性和特點(diǎn):
使用內(nèi)部類最吸引人的原因是:每個(gè)內(nèi)部類都能獨(dú)立地實(shí)現(xiàn)某一接口吧碾,所以無論外部類是否已經(jīng)實(shí)現(xiàn)了某個(gè)接口,對(duì)于內(nèi)部類都沒有影響墓卦。接口和內(nèi)部類配合使用倦春,使得多繼承的解決方案變得更加完整。

① 我們都知道類一般都不聲明成private和protected落剪,但是內(nèi)部類可以睁本,所以通過內(nèi)部類可以很好地隱藏我們的信息。
② 內(nèi)部類它可以直接訪問外部類的成員變量和方法(甚至是私有的)忠怖,利用這個(gè)特性呢堰,配合接口,我們可以更好地實(shí)現(xiàn)多繼承的效果凡泣。
③ 內(nèi)部類聲明成靜態(tài)的枉疼,就不能隨便訪問外部類的成員數(shù)據(jù)了,此時(shí)內(nèi)部類只能訪問外部類的靜態(tài)成員數(shù)據(jù)鞋拟。
④ 在編譯成功之后骂维,它就與外部類是不同的類,是一個(gè)獨(dú)立的類贺纲,當(dāng)然他們之間還是有聯(lián)系的航闺。在編譯之后內(nèi)部類會(huì)被編譯成獨(dú)立的.class文件,前面冠以外部類的類名和$符號(hào)哮笆。

在這里我要詳細(xì)解釋下上面的第二點(diǎn)和第三點(diǎn):

  • 靜態(tài)內(nèi)部類雖然定義在外部類的里面来颤, 但是它只是在形式上(寫法上)和外部類有關(guān)系,其實(shí)在邏輯上和外部類并沒有直接的關(guān)系稠肘,它并不依賴外部類福铅。雖然它也能訪問外部類的靜態(tài)數(shù)據(jù),這是因?yàn)樵诰幾g的時(shí)候项阴,就已經(jīng)做到數(shù)據(jù)共享了滑黔。

  • 而一般的內(nèi)部類,不僅在形式上和外部類有關(guān)系(寫在外部類的里面)环揽, 在邏輯上也和外部類有聯(lián)系略荡。這種邏輯關(guān)系主要表現(xiàn)在:內(nèi)部類對(duì)象的創(chuàng)建依賴于外部類對(duì)象,內(nèi)部類對(duì)象持有指向外部類對(duì)象的引用歉胶。

至于為什么會(huì)持有外部類對(duì)象的引用汛兜,以后會(huì)再專門拿出篇幅進(jìn)行說明,這里就先不做介紹了通今。

根據(jù)不同的區(qū)分方法粥谬,總的來說可以分為成員內(nèi)部類(普通內(nèi)部類)、靜態(tài)內(nèi)部類辫塌、局部內(nèi)部類漏策、匿名內(nèi)部類。

一臼氨、成員內(nèi)部類

概念:
成員內(nèi)部類是跟外部類的成員變量和方法同級(jí)的內(nèi)部類掺喻。成員內(nèi)部類的修飾詞跟外部類的成員變量及方法的權(quán)限修飾詞的作用是一樣的。

用法特征:
① 成員內(nèi)部類與外部類的實(shí)例相聯(lián)系储矩,可以訪問外部類的所有成員數(shù)據(jù)(包括外部類中的 private成員)感耙。正因?yàn)槌蓡T內(nèi)部類與外部類的實(shí)例聯(lián)系,因此不能在其內(nèi)部定義靜態(tài)成員變量椰苟。
② 非靜態(tài)內(nèi)部類的創(chuàng)建需要依賴于外部類抑月。

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

概念:
跟成員內(nèi)部類不同的是:他是由static來修的類舆蝴,叫做靜態(tài)內(nèi)部類谦絮。

用法特征:
靜態(tài)內(nèi)部類與非靜態(tài)內(nèi)部類之間存在一個(gè)最大的區(qū)別,我們知道非靜態(tài)內(nèi)部類在編譯完成之后會(huì)隱含地保存著一個(gè)引用洁仗,該引用是指向創(chuàng)建它的外部類层皱,但是靜態(tài)內(nèi)部類卻沒有。沒有這個(gè)引用就意味著:
① 靜態(tài)內(nèi)部類不能直接訪問外部類的非靜態(tài)成員赠潦,靜態(tài)內(nèi)部類可以直接訪問外部類的靜態(tài)成員數(shù)據(jù)叫胖。
③ 靜態(tài)內(nèi)部類可以直接創(chuàng)建實(shí)例,不需要依賴于外部類她奥。

三瓮增、局部內(nèi)部類

概念:
即在方法中定義的內(nèi)部類怎棱,與局部變量類似,其范圍為定義它的代碼塊绷跑。

用法特征:
① 局部內(nèi)部類可以訪問外部類的所有成員數(shù)據(jù)和方法內(nèi)的數(shù)據(jù)拳恋。
② 局部內(nèi)部類訪問局部變量和形參時(shí),局部變量和形參必須修飾為final砸捏。
③ 局部內(nèi)部類和普通內(nèi)部類是相似的谬运,因?yàn)樗麄兌疾荒芏x靜態(tài)成員數(shù)據(jù)(靜態(tài)常量除外)。如果局部內(nèi)部類在靜態(tài)方法內(nèi)被定義垦藏,那么這個(gè)局部內(nèi)部類就只能訪問方法的靜態(tài)成員梆暖。
④ 不能在局部內(nèi)部類中聲明接口,因?yàn)榻涌诒旧砭褪庆o態(tài)的掂骏。
⑤ 局部內(nèi)部類只能在定義該內(nèi)部類的方法內(nèi)實(shí)例化轰驳,不可以在此方法外對(duì)其實(shí)例化。

在這里解釋下上面的第二點(diǎn):
局部內(nèi)部類訪問局部變量和形參時(shí)芭挽,局部變量和形參必須修飾為final滑废。這是因?yàn)榉椒ǖ木植孔兞课挥跅I希淮嬖谟谠摲椒ǖ纳趦?nèi)袜爪。當(dāng)一個(gè)方法結(jié)束蠕趁,其棧結(jié)構(gòu)被刪除,局部變量成為歷史辛馆。但是該方法結(jié)束之后俺陋,在方法內(nèi)創(chuàng)建的內(nèi)部類對(duì)象可能仍然存在于堆中!正因?yàn)椴荒鼙WC局部變量的存活期和方法內(nèi)部類對(duì)象的一樣長昙篙,所以內(nèi)部類對(duì)象不能使用它們腊状。

在Java SE8中,不再需要這樣了苔可,只要局部變量和形參不被二次賦值即可缴挖。

四、匿名內(nèi)部類

概念:
沒有名字的內(nèi)部類焚辅。形式參考代碼示例映屋。
語法:
new 實(shí)現(xiàn)接口()|父類構(gòu)造器(實(shí)參列表)
{
//匿名內(nèi)部類的實(shí)體部分
}
用法特征:
① 匿名內(nèi)部類特別適合于只使用一次的類。
② 使用匿名內(nèi)部類時(shí)同蜻,我們必須是繼承一個(gè)類或者實(shí)現(xiàn)一個(gè)接口棚点,但是兩者不可兼得,同時(shí)也只能繼承一個(gè)類或者實(shí)現(xiàn)一個(gè)接口湾蔓。
③ 匿名內(nèi)部類內(nèi)部不能有構(gòu)造方法瘫析。
④ 匿名內(nèi)部類中不能存在任何的靜態(tài)成員變量和靜態(tài)方法。
⑤ 匿名類和局部內(nèi)部類一樣,可以訪問外部類的成員(必須是final或沒有二次賦值的成員)贬循。

java8以前咸包,Java要求被局部內(nèi)部類,匿名內(nèi)部類訪問的局部變量必須使用final修飾杖虾,java8以后诉儒,這個(gè)限制取消了!

應(yīng)用場(chǎng)景及注意事項(xiàng):
當(dāng)我們只需要類的一個(gè)實(shí)例亏掀,且類在定義以后會(huì)馬上被用到,代碼量少泛释,寫上匿名內(nèi)部類會(huì)優(yōu)化程序結(jié)構(gòu)滤愕,并符合以上的那些用法特征的時(shí)候,可以考慮用匿名內(nèi)部類怜校。

  • 對(duì)于匿名內(nèi)部類的使用它是存在一個(gè)缺陷的间影,就是它僅能被使用一次,創(chuàng)建匿名內(nèi)部類時(shí)它會(huì)立即創(chuàng)建一個(gè)該類的實(shí)例茄茁,該類的定義會(huì)立即消失魂贬,所以匿名內(nèi)部類是不能夠被重復(fù)使用。

  • 匿名內(nèi)部類是唯一一種沒有構(gòu)造器的類裙顽。正因?yàn)槠錄]有構(gòu)造器付燥,所以匿名內(nèi)部類的使用范圍非常有限,大部分匿名內(nèi)部類用于接口回調(diào)愈犹。一般來說键科,匿名內(nèi)部類用于繼承其他類或是實(shí)現(xiàn)接口,并不需要增加額外的方法漩怎,只是對(duì)繼承方法的實(shí)現(xiàn)或是重寫勋颖。

  • 有一點(diǎn)需要注意的是,匿名內(nèi)部類由于沒有名字勋锤,所以它沒有構(gòu)造函數(shù)(但是如果這個(gè)匿名內(nèi)部類繼承了一個(gè)只含有帶參數(shù)構(gòu)造函數(shù)的父類饭玲,創(chuàng)建它的時(shí)候必須帶上這些參數(shù),并在實(shí)現(xiàn)的過程中使用super關(guān)鍵字調(diào)用相應(yīng)的內(nèi)容)叁执。如果你想要初始化它的成員變量茄厘,有下面幾種方法:
    ① 如果是在一個(gè)方法的匿名內(nèi)部類,可以利用這個(gè)方法傳進(jìn)你想要的參數(shù)徒恋。
    ② 將匿名內(nèi)部類改造成有名字的局部內(nèi)部類蚕断,這樣它就可以擁有構(gòu)造函數(shù)了。
    ③ 在這個(gè)匿名內(nèi)部類中使用初始化代碼塊入挣。

五亿乳、代碼示例

//OuterClass類
public class OuterClass {
    
    private static String outerStaticStr;
    private int outerInt;
    
    // 普通方法
    public void outerDisplay(){
        System.out.println("OuterClass outerDisplay Method");
    }
    
    // 靜態(tài)方法
    public static void outerStaticDisplay(){
        System.out.println("OuterClass outerStaticDisplay Method");
    }

    /*成員內(nèi)部類*/
    public class InnerClass{
        public String innerStr; //成員內(nèi)部類不能聲明靜態(tài)變量
        static final int innerInt = 100; // 靜態(tài)常量
        public void innerDisplay(){
            outerStaticStr = "Tom";  // 使用外部類的成員變量
            System.out.println("成員內(nèi)部類 " + outerStaticStr);
            outerDisplay();// 使用外部類的方法
            outerStaticDisplay();
        }
    }

    /*靜態(tài)內(nèi)部類*/
    public static class StaticInnerClass {
        private String innerStr;
        public static String innerStaticStr; // 與成員內(nèi)部類不同,靜態(tài)內(nèi)部類可以聲明靜態(tài)變量
        public void innerDisplay() {
            //靜態(tài)內(nèi)部類可以直接訪問外部類的靜態(tài)成員數(shù)據(jù)。
            outerStaticStr = "Jerry";
            System.out.println("靜態(tài)內(nèi)部類 " + outerStaticStr);
            outerStaticDisplay();
        }
    }

    /*局部內(nèi)部類*/
    public void outPut(String string) {
        int a = 20;
        outerInt = 999;
        class LocalInnerClass { // 此時(shí)局部內(nèi)部類與局部變量同一等級(jí)葛假,局部不能加private等權(quán)限訪問修飾詞修飾障陶。
            static final int b = 20; //靜態(tài)常量
            public void localOutPut() {
                //string = "局部內(nèi)部類"; //不能再賦值
                //a = 30; //不能再賦值
                System.out.println(string);
                System.out.println(outerInt);
            }
        }
        // 只能在方法內(nèi)實(shí)例化
        LocalInnerClass localInner = new LocalInnerClass();
        localInner.localOutPut();
    }

    /*匿名內(nèi)部類*/
    public void test(Person per){
        System.out.println(per.getName() + "今天走了" + per.walk() + "米。");
    }
    

    public InnerClass getInnerClass(){
        return new InnerClass();
    }
    public StaticInnerClass getStaticInnerClass(){
        return new StaticInnerClass();
    }

}
public class Main {

    public static void main(String[] args) {
        
        OuterClass outer = new OuterClass();
        //OuterClass.InnerClass inner = outer.getInnerClass();
        OuterClass.InnerClass inner = new OuterClass().new InnerClass();// 非靜態(tài)內(nèi)部類的創(chuàng)建需要依賴于外部類聊训。
        inner.innerDisplay();

        OuterClass.StaticInnerClass staticInner = outer.getStaticInnerClass();
        staticInner.innerDisplay();

        outer.outPut("局部內(nèi)部類");

        /*匿名內(nèi)部類*/
       outer.test(new Person() {

            public int walk() { // 實(shí)現(xiàn)抽象方法
                return 500;
            }

            public String getName() { // 重寫方法
                return "小明";
            }
        });

       /*
       * test()方法接受一個(gè)Person類型的參數(shù)抱究,同時(shí)我們知道一個(gè)抽象類是沒有辦法直接new的。
       * 我們必須要先有實(shí)現(xiàn)類才能new出來它的實(shí)現(xiàn)類實(shí)例带斑。
       * 所以在方法中直接使用匿名內(nèi)部類來創(chuàng)建一個(gè)Person實(shí)例鼓寺。
       * 由于匿名內(nèi)部類不能是抽象類,所以它必須要實(shí)現(xiàn)它的抽象父類或者接口里面所有的抽象方法勋磕。
       * */

    }
}
public abstract class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract int walk();
}

寫完嘍妈候!ㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏㄟ(▔,▔)ㄏ


知識(shí)重在總結(jié)和梳理,只有不斷地去學(xué)習(xí)并運(yùn)用挂滓,才能化為自己的東西苦银。當(dāng)你能為別人講明白的時(shí)候,說明自己已經(jīng)掌握了赶站。

歡迎轉(zhuǎn)載幔虏,轉(zhuǎn)載請(qǐng)注明出處!

如果有錯(cuò)誤的地方贝椿,或者有您的見解想括,還請(qǐng)不嗇賜教!

喜歡的話烙博,麻煩點(diǎn)個(gè)贊主胧!

本文部分參考了:http://blog.csdn.net/chenssy/article/details/13170015

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市习勤,隨后出現(xiàn)的幾起案子踪栋,更是在濱河造成了極大的恐慌,老刑警劉巖图毕,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件夷都,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡予颤,警方通過查閱死者的電腦和手機(jī)囤官,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蛤虐,“玉大人党饮,你說我怎么就攤上這事〔低ィ” “怎么了刑顺?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵氯窍,是天一觀的道長。 經(jīng)常有香客問我蹲堂,道長狼讨,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任柒竞,我火速辦了婚禮政供,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朽基。我一直安慰自己布隔,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布稼虎。 她就那樣靜靜地躺著执泰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪渡蜻。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天计济,我揣著相機(jī)與錄音茸苇,去河邊找鬼。 笑死沦寂,一個(gè)胖子當(dāng)著我的面吹牛学密,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播传藏,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼腻暮,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了毯侦?” 一聲冷哼從身側(cè)響起哭靖,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侈离,沒想到半個(gè)月后试幽,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卦碾,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年铺坞,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洲胖。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡济榨,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出绿映,到底是詐尸還是另有隱情擒滑,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站橘忱,受9級(jí)特大地震影響赴魁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜钝诚,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一颖御、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧凝颇,春花似錦潘拱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至垫蛆,卻和暖如春禽最,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背袱饭。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工川无, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人虑乖。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓懦趋,卻偏偏與公主長得像,于是被迫代替她去往敵國和親疹味。 傳聞我的和親對(duì)象是個(gè)殘疾皇子仅叫,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

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

  • Java 內(nèi)部類 分四種:成員內(nèi)部類、局部內(nèi)部類糙捺、靜態(tài)內(nèi)部類和匿名內(nèi)部類诫咱。 1、成員內(nèi)部類: 即作為外部類的一個(gè)成...
    ikaroskun閱讀 1,223評(píng)論 0 13
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法洪灯,類相關(guān)的語法遂跟,內(nèi)部類的語法,繼承相關(guān)的語法婴渡,異常的語法幻锁,線程的語...
    子非魚_t_閱讀 31,598評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit边臼,java的開發(fā)和運(yùn)行環(huán)境哄尔,java的開發(fā)工...
    ZaneInTheSun閱讀 2,635評(píng)論 0 11
  • 高鐵一路飛馳,窗外延綿的農(nóng)田快速閃過柠并×虢樱靠窗的張茂的凝神望著遠(yuǎn)處富拗,滿臉心事重重。 他的心從來沒有這么忐忑和無主過鸣戴。他...
    林四月閱讀 1,318評(píng)論 0 2
  • 關(guān)于宮崎駿的動(dòng)畫啃沪,人們可以寫出很多的溢美之詞,我不多贅述窄锅。然而在看過宮老大多數(shù)的動(dòng)畫電影之后创千,對(duì)他的片中流露出的對(duì)...
    魔鬼的贊歌閱讀 2,063評(píng)論 9 18