一、概述
我們知道,Java是一種完全的面向對象的語言,作為對象的靈魂,類的種類是多種多樣的。類大緻可以分外部類和内部類兩種,外部類就是我們通常使用的類,而内部類的使用要比外部類少得多,最常見的是GUI事件偵聽器。内部類的應用雖然不多,但是如果能夠有效地使用内部類,能達到事半功倍的效果。
二、内部類和嵌套類
要讨論内部類和嵌套類,首先要厘清它們兩者的差別與聯系。
首先,内部類(Inner Classes)和嵌套類(Nested Classes)是指在一個類裡面定義的另一個類。其次,無論是内部類還是嵌套類,在編譯時都被當作一個獨立的整體。對于通路它們的其他對象來說(假如它們對這個類來說是可見的)它們的使用和我們通常用的類是一樣的。
但是,内部類和嵌套類的差別在于:
- 嵌套類是靜态的,而内部類不是,也就是說嵌套類的執行個體化不需要外部類的執行個體,但是内部類是需要這個執行個體的。
- 嵌套類可以任意聲明靜态成員,内部類不允許聲明除了編譯時常量以外的任何靜态成員。這一限制也适用于靜态初始化函數。
- 嵌套類都是命名的,匿名的類聲明不能聲明運作時靜态成員(不管聲明是不是靜态的)。 注意:類内部聲明的接口都屬于嵌套類。
下面我們來分别讨論一下它們的具體行為表現。
三、内部類
内部類是指在一個類裡面以非靜态形式聲明的另一個類。内部類的執行個體化需要外部執行個體的存在。一個類可以擁有多個内部類,一個外部執行個體可以擁有多個内部類的執行個體。但是内部類有且隻有一個外部執行個體,并且在執行個體化時就已經指定,無法更改。
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