天天看點

内部類與嵌套類

一、概述

我們知道,Java是一種完全的面向對象的語言,作為對象的靈魂,類的種類是多種多樣的。類大緻可以分外部類和内部類兩種,外部類就是我們通常使用的類,而内部類的使用要比外部類少得多,最常見的是GUI事件偵聽器。内部類的應用雖然不多,但是如果能夠有效地使用内部類,能達到事半功倍的效果。

二、内部類和嵌套類

要讨論内部類和嵌套類,首先要厘清它們兩者的差別與聯系。

首先,内部類(Inner Classes)和嵌套類(Nested Classes)是指在一個類裡面定義的另一個類。其次,無論是内部類還是嵌套類,在編譯時都被當作一個獨立的整體。對于通路它們的其他對象來說(假如它們對這個類來說是可見的)它們的使用和我們通常用的類是一樣的。

但是,内部類和嵌套類的差別在于:

  1. 嵌套類是靜态的,而内部類不是,也就是說嵌套類的執行個體化不需要外部類的執行個體,但是内部類是需要這個執行個體的。
  2. 嵌套類可以任意聲明靜态成員,内部類不允許聲明除了編譯時常量以外的任何靜态成員。這一限制也适用于靜态初始化函數。
  3. 嵌套類都是命名的,匿名的類聲明不能聲明運作時靜态成員(不管聲明是不是靜态的)。 注意:類内部聲明的接口都屬于嵌套類。

下面我們來分别讨論一下它們的具體行為表現。​

三、内部類

内部類是指在一個類裡面以非靜态形式聲明的另一個類。内部類的執行個體化需要外部執行個體的存在。一個類可以擁有多個内部類,一個外部執行個體可以擁有多個内部類的執行個體。但是内部類有且隻有一個外部執行個體,并且在執行個體化時就已經指定,無法更改。

1. 内部類的分類

内部類根據通路權限不同可以分為以下兩種類型:普通内部類和局部内部類。

普通内部類和局部内部類主要的差別在于作用域和通路權限的不同,普通内部類可以被所有人通路(隻要通路控制符允許),而局部内部類的作用域更像一個變量,隻能在定義它的函數内部被使用,其他人是無法使用這個類的。而且局部類可以通路定義它的函數中的final變量。

内部類根據聲明方式不同又可以分為:命名内部類和匿名内部類。

命名内部類和匿名内部類的差別在于:

首先,命名類可以抽象的。匿名類不能為抽象,事實上,匿名内部類在編譯時被隐形地聲明為最終的(final)。

其次,命名類聲明可以繼承一個父類并實作多個接口,匿名類隻能有一個父類(或者接口)。

再次,命名類可以被多次執行個體化,而匿名類隻能在定義時被執行個體化一次。最後,命名類可以聲明多個構造函數并控制通路哪一個父類的構造函數,匿名類無法聲明構造函數。

下面分别描述這些差別:​

2. 普通内部類

普通内部類是指在類成員定義中定義的類,這些類可以擁有通路控制符(public, private等)。如果通路控制符允許,則這些類可以被外面直接應用。普通命名内部類可以聲明為一個接口,或者是抽象的。嵌套類其實是特殊的普通内部類,但由于其特殊性,故在下面獨立讨論。

聲明:

命名類:​

class OuterClass{

    //Outer class definition       

    class InnerNamedClass{                

          //Inner class definition 

    } 

}​​
           

匿名類:

//聲明匿名類時,可以使用一個類或者接口作為它的父類

class OuterClass{

     //Outer class definition

     Object unnamedObject = new Object(){         

           //Inner class definition    

     } 

}​
           

執行個體化:

命名類:

//外部或靜态方法:

OuterClass outerObject = new OuterClass();

OuterClass.InnerNamedClass innerObject = outerObject.new InnerNamedClass();

//内部:

InnerNamedClass innerObject = new InnerNamedClass();
           

匿名類:

定義時即完成執行個體化​

通路權限:​

  • 内部執行個體對外部執行個體的通路權限為:外部類定義或繼承的所有字段
  • 外部執行個體對内部執行個體的通路權限為:内部類定義或繼承的所有字段
  • 其他對象對内部執行個體的通路權限為:若内部類不可見,則隻能通路其超類定義的字段;若内部類可見,則可通路内部執行個體的非私有字段,具體情況與通常的類類似​

備注:

内部類的外部執行個體是在構造時作為參數傳給構造函數的,在SUN JDK中,儲存外部執行個體的字段通常被聲明為:

final OutterClass this$;​
           

3. 局部内部類

局部内部類,是指在函數體内聲明的類,這種類是局域性的,隻在函數内聲明後有效,它最大的特點是:可以通路定義它的函數中的final變量。

聲明:

命名類:​

class OuterClass{

      //Outer class definition     

      void aMethod(){         

            class InnerNamedClass{             

                //Inner class definition

           }     

    } 

}​
           

匿名類:

class OuterClass{

         //Outer class definition     

         void aMethod(){

              Object unnamedObject = new Object(){             

                  //Inner class definition         

              }     

        } 

}​
           

執行個體化:

命名類:局部類的作用域僅限定義該類的方法中,無法在外部執行個體化或通路,執行個體化方法與通常類相同

匿名類: 定義時即完成執行個體化​

通路權限:

  • 内部執行個體對外部執行個體的通路權限為: 外部類定義或繼承的所有字段;定義該内部類的方法在定義類之前所定義的所有final變量
  • 外部執行個體對内部執行個體的通路權限為:在定義該内部類的方法中可以通路内部類定義或繼承的所有字段,在外部執行個體的其他字段中隻能通路其超類定義的字段
  • 其他對象對内部執行個體的通路權限為: 隻能通路其超類定義的字段​

備注:

當試圖通路一個final變量時,編譯器實際上把該變量的值指派給内部類的一個隐含字段中。編譯器會自動地在構造函數中添加相應的參數。在SUN JDK中,這個隐含字段通常被命名為:val$varname​

4. 使用内部類的注意事項:

本節包括了一些使用内部類時需要注意的事項,這些事項對所有内部類都适用。

靜态成員

首先需要注意的是,内部類不能聲明非常量靜态成員,任何靜态成員的聲明都會被當成編譯錯誤,例如:static String a;

通路外部執行個體

要在一個内部執行個體中通路外部執行個體,請使用:OuterClass.this

字段覆寫

在内部類中聲明的與外部類同簽名的字段将覆寫外部字段,要通路外部字段請使用外部執行個體對象字首。

OuterClass.this.field     

OuterClass.this.Method();​​
           

四、嵌套類

嵌套類(Nested Classes)其實是普通内部類的一種特殊形式。首先它的聲明是靜态的,這就表示了這個類不需要外部執行個體,也表示了它不能通路外部類的執行個體字段。但是相應的,嵌套類可以擁有非常量靜态成員。事實上,JDK通常把嵌套類當成一個具有特殊名字的獨立類。

另外,嵌套類還擁有一種特殊形式:匿名嵌套類。前面說過,匿名類都是内部類,但是匿名嵌套類是一個特例,從理論上講,它既不屬于嵌套類,也不屬于内部類。匿名嵌套類不允許擁有非常量靜态成員,但是它也沒有外部執行個體供通路。

聲明:

命名類:

class OuterClass{

        //Outer class definition       

        static class StaticInnerNamedClass{                

               //Inner class definition 

        }

 }​
           

匿名類:

class OuterClass{

        //Outer class definition

        static Object unnamedObject = new Object(){         

            //Inner class definition     

       }

 }​
           

執行個體化:

内部:

StaticInnerNamedClass staticInnerNamedObject = new StaticInnerNamedClass();
           

外部:

OuterClass.StaticInnerNamedClass staticInnerNamedObject = new OuterClass.StaticInnerNamedClass();
           

匿名嵌套類在聲明時即完成執行個體化。

轉自:http://wenku.baidu.com/link?url=CAO7ZeLvcastqnJgKPjITaU4A261xxit8Ivw3EQ6sltGn_VKy-9k6VLBCZQkQC5vK6abyjRTv8YmMh3AYLsGCWy9KAQtD93q1e8BDcuCxfy