官术网_书友最值得收藏!

第5章 Java內(nèi)部的秘密——內(nèi)部類

◎ 本章教學(xué)微視頻:6個(gè) 25分鐘

學(xué)習(xí)指引

在Java中,允許在一個(gè)類的內(nèi)部定義類,這樣的類稱作內(nèi)部類,內(nèi)部類所在的類稱作外部類。根據(jù)內(nèi)部類的位置、修飾符和定義的方式可以將內(nèi)部類分為不同類型。本章介紹Java的內(nèi)部類,主要內(nèi)容包括創(chuàng)建內(nèi)部類、鏈接到外部類、成員內(nèi)部類、匿名內(nèi)部類、局部?jī)?nèi)部類和靜態(tài)內(nèi)部類等。

重點(diǎn)導(dǎo)讀

  • 掌握創(chuàng)建內(nèi)部類的方法。
  • 掌握鏈接到外部類的方法。
  • 掌握成員內(nèi)部類的使用方法。
  • 掌握匿名內(nèi)部類的使用方法。
  • 掌握局部?jī)?nèi)部類的使用方法。
  • 掌握靜態(tài)內(nèi)部類的使用方法。

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

內(nèi)部類就是在一個(gè)類的內(nèi)部再定義一個(gè)類。內(nèi)部類可以是靜態(tài)的,也可以用public、default、protected和private修飾,而外部類只能使用public和default修飾。

內(nèi)部類是一個(gè)編譯時(shí)的概念,一旦編譯成功,就會(huì)和相應(yīng)的外部類成為完全不同的兩個(gè)類。對(duì)于一個(gè)名為OuterTest的外部類和其內(nèi)部定義的名為Inner的內(nèi)部類,編譯完成后出現(xiàn)OuterTest.class和OuterTest$Inner.class兩個(gè)類。所以內(nèi)部類的成員變量、方法名可以和外部類的相同。

下面舉例說明如何創(chuàng)建和實(shí)例化內(nèi)部類。

【例5-1】(實(shí)例文件:ch05\Chap5.1.txt)創(chuàng)建內(nèi)部類應(yīng)用實(shí)例。

     public class OuterC {
         public void showOuterC() {
             System.out.println("這是外部類");
         }
         public class InnerC {
             public void showInnerC() {
                 System.out.println("這是內(nèi)部類");
             }
         }
     }

在本例中,OuterC是一個(gè)外部類,在該類中定義了一個(gè)內(nèi)部類InnerC和一個(gè)showOuterC()方法,其中,InnerC類有一個(gè)showInnerC()方法。

5.2 鏈接到外部類

如果想通過外部類訪問內(nèi)部類,則需要通過外部類對(duì)象創(chuàng)建內(nèi)部類對(duì)象。創(chuàng)建內(nèi)部類對(duì)象的具體語法格式如下:

     外部類名.內(nèi)部類名 對(duì)象名 = new 外部類名().new 內(nèi)部類名();

下面通過一個(gè)例子來具體說明。

【例5-2】(實(shí)例文件:ch05\Chap5.2.txt)實(shí)例化內(nèi)部類(每個(gè)類均為單獨(dú)的文件)。

程序運(yùn)行結(jié)果如圖5-1所示。

圖5-1 實(shí)例化內(nèi)部類運(yùn)行結(jié)果

本例通過OuterC.InnerC ic = new OuterC().new InnerC();來創(chuàng)建內(nèi)部類對(duì)象ic,并調(diào)用內(nèi)部類的showInnerC()方法將內(nèi)容顯示在控制臺(tái)上。

5.3 成員內(nèi)部類

在一個(gè)類中除了可以定義成員變量、成員方法,還可以定義類,這樣的類就被稱作成員內(nèi)部類,成員內(nèi)部類是最普通的內(nèi)部類。在成員內(nèi)部類中可以訪問外部類的所有成員。成員內(nèi)部類的使用方法如下:

  • 成員內(nèi)部類定義在外部類的內(nèi)部,相當(dāng)于外部類的一個(gè)成員變量,成員內(nèi)部類可以使用任意訪問控制符,如public、protected、private等。
  • 成員內(nèi)部類的方法可以直接訪問外部類的所有數(shù)據(jù),包括私有的數(shù)據(jù)。
  • 定義了成員內(nèi)部類后,必須使用外部類對(duì)象來創(chuàng)建內(nèi)部類對(duì)象。即:
     內(nèi)部類 對(duì)象名=外部類對(duì)象.new內(nèi)部類();
  • 成員內(nèi)部類class文件格式為“外部類名$內(nèi)部類名.class”。

另外,還有一些規(guī)定如下:

  • 外部類不能直接使用內(nèi)部類的成員和方法。可先創(chuàng)建內(nèi)部類的對(duì)象,然后通過內(nèi)部類的對(duì)象來訪問其成員變量和方法。
  • 如果外部類和內(nèi)部類具有相同的成員變量或方法,內(nèi)部類默認(rèn)訪問自己的成員變量或方法。如果內(nèi)部類要訪問外部類的成員變量,可以使用this關(guān)鍵字(內(nèi)部類默認(rèn)可以引用外部類對(duì)象,引用時(shí)在對(duì)象名前面加上“外部類名.this”)。
  • 外部類的外部要聲明完整,如外部類名.內(nèi)部類名,外部類內(nèi)部則不需要。

【例5-3】(實(shí)例文件:ch05\Chap5.3.txt)成員內(nèi)部類實(shí)例。

程序運(yùn)行結(jié)果如圖5-2所示。

圖5-2 成員內(nèi)部類運(yùn)行結(jié)果

本例中,外部類定義了變量b=5,內(nèi)部類也定義了變量b=3,因此內(nèi)部類如果要訪問外部類的變量b,必須通過Outer.this.b才能訪問。

另外,成員內(nèi)部類是依附外部類而存在的,也就是說,如果要?jiǎng)?chuàng)建成員內(nèi)部類的對(duì)象,前提是必須存在一個(gè)外部類的對(duì)象。因此,通過Outer o = new Outer();先創(chuàng)建了外部類對(duì)象,然后通過Inner i = o.new Inner();創(chuàng)建了內(nèi)部類對(duì)象。

5.4 匿名內(nèi)部類

匿名內(nèi)部類就是沒有名字的內(nèi)部類,多用于關(guān)注實(shí)現(xiàn)而不關(guān)注實(shí)現(xiàn)類的名稱。匿名內(nèi)部類一般是編寫代碼時(shí)用得最多的內(nèi)部類。在Swing編程中,經(jīng)常使用這種方式來綁定事件,在編寫事件監(jiān)聽的代碼時(shí)使用匿名內(nèi)部類不但方便,而且使代碼更加容易維護(hù)。

【例5-4】(實(shí)例文件:ch05\Chap5.4.txt)匿名內(nèi)部類實(shí)例。

     button2.addActionListener(
           new ActionListener(){
               public void actionPerformed(ActionEvent e) {
                   System.out.println("單擊了button2");
               }
     });

本例中,為一個(gè)按鈕對(duì)象button2添加了一個(gè)事件監(jiān)聽器,addActionListener()方法的參數(shù)是一個(gè)匿名內(nèi)部類:

     new ActionListener(){
           public void actionPerformed(ActionEvent e) {
                System.out.println("單擊了button2");
           }
     }

匿名內(nèi)部類是唯一的沒有構(gòu)造器的類。正因?yàn)槠錄]有構(gòu)造器,所以匿名內(nèi)部類的使用范圍非常有限,大部分匿名內(nèi)部類用于接口回調(diào)。匿名內(nèi)部類在編譯的時(shí)候由系統(tǒng)自動(dòng)命名為Outter$1.class。一般來說,匿名內(nèi)部類用于繼承其他類或用于實(shí)現(xiàn)接口,并不需要增加額外的方法,因?yàn)樗皇菍?duì)繼承方法的實(shí)現(xiàn)或重寫。

5.5 局部?jī)?nèi)部類

局部?jī)?nèi)部類是定義在一個(gè)方法或者一個(gè)作用域中的類,它和成員內(nèi)部類的區(qū)別在于局部?jī)?nèi)部類的訪問僅限于方法內(nèi)或者該作用域內(nèi)。注意,局部?jī)?nèi)部類就像是方法中的一個(gè)局部變量一樣,是不能有public、protected、private以及static修飾符的。

【例5-5】(實(shí)例文件:ch05\Chap5.5.txt)局部?jī)?nèi)部類舉例:定義在方法內(nèi)。

【例5-6】(實(shí)例文件:ch05\Chap5.6.txt)局部?jī)?nèi)部類舉例:定義在作用域內(nèi)。

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

靜態(tài)內(nèi)部類也是定義在另一個(gè)類中的類,只不過在類的前面多了一個(gè)關(guān)鍵字static。靜態(tài)內(nèi)部類是不需要依賴于外部類的,這一點(diǎn)和類的靜態(tài)成員屬性有點(diǎn)類似,并且它不能使用外部類的非靜態(tài)成員變量或者方法,因?yàn)樵跊]有外部類的對(duì)象的情況下,可以創(chuàng)建靜態(tài)內(nèi)部類的對(duì)象,如果允許訪問外部類的非靜態(tài)成員就會(huì)產(chǎn)生矛盾,因?yàn)橥獠款惖姆庆o態(tài)成員必須依附于具體的對(duì)象。

  • 靜態(tài)內(nèi)部類是static修飾的內(nèi)部類,這種內(nèi)部類的特點(diǎn)如下:
  • 靜態(tài)內(nèi)部類不能直接訪問外部類的非靜態(tài)成員,但可以通過“new外部類().成員”的方式訪問。
  • 如果外部類的靜態(tài)成員與內(nèi)部類的成員名稱相同,可通“類名.靜態(tài)名”訪問外部類的靜態(tài)成員;否則可通過成員名直接調(diào)用外部類的靜態(tài)成員。
  • 創(chuàng)建靜態(tài)內(nèi)部類中的對(duì)象時(shí),不需要外部類的對(duì)象,可以直接創(chuàng)建,格式為

內(nèi)部類名 對(duì)象名=new內(nèi)部類名();

  • 在其他類中創(chuàng)建內(nèi)部類的對(duì)象時(shí),不需要用外部類對(duì)象創(chuàng)建,格式為

外部類名.內(nèi)部類名 對(duì)象名=new外部類名.內(nèi)部類名();

【例5-7】(實(shí)例文件:ch05\Chap5.7.txt)靜態(tài)內(nèi)部類舉例。

程序運(yùn)行結(jié)果如圖5-3所示。

圖5-3 靜態(tài)內(nèi)部類運(yùn)行結(jié)果

本例中,內(nèi)部類訪問外部類的靜態(tài)成員變量b可以通過Outer.b實(shí)現(xiàn),內(nèi)部類訪問外部類的非靜態(tài)成員變量a必須通過new Outer().a來實(shí)現(xiàn)。在Java中需要使用內(nèi)部類的原因主要有以下4點(diǎn):

  • 每個(gè)內(nèi)部類都能獨(dú)立地繼承一個(gè)接口的實(shí)現(xiàn),所以無論外部類是否已經(jīng)繼承了某個(gè)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒有影響。內(nèi)部類使得多繼承的解決方案變得更加完善。
  • 方便將存在一定邏輯關(guān)系的類組織在一起,又可以對(duì)外界隱藏。
  • 方便編寫事件驅(qū)動(dòng)程序。
  • 方便編寫線程代碼。

5.7 就業(yè)面試解析與技巧

5.7.1 面試解析與技巧(一)

面試官:創(chuàng)建了匿名類,為什么編譯時(shí)提示匿名類不存在呢?

應(yīng)聘者:創(chuàng)建匿名類時(shí),首先要?jiǎng)?chuàng)建匿名類的接口,否則編譯時(shí)提示匿名類不存在。

5.7.2 面試解析與技巧(二)

面試官:成員內(nèi)部類和靜態(tài)內(nèi)部類有什么區(qū)別?

應(yīng)聘者:成員內(nèi)部類的創(chuàng)建必須依賴于外部類,靜態(tài)內(nèi)部類的創(chuàng)建不依賴于外部類。成員內(nèi)部類可以訪問外部類的所有成員,靜態(tài)內(nèi)部類只可以訪問外部類的靜態(tài)成員變量和靜態(tài)的方法。

主站蜘蛛池模板: 昆明市| 五寨县| 江口县| 金秀| 湟源县| 金湖县| 徐水县| 宜兰市| 元阳县| 开封县| 洞口县| 密山市| 玉溪市| 上虞市| 广元市| 从江县| 芜湖县| 淳化县| 安福县| 桑日县| 新密市| 保山市| 哈尔滨市| 仁化县| 双柏县| 武义县| 普兰县| 涪陵区| 如东县| 呈贡县| 门头沟区| 贵德县| 邢台市| 启东市| 龙山县| 和政县| 高雄县| 高清| 西丰县| 汉沽区| 滦南县|