在Java中,定義在一個類里面或者一個方法里面的類 叫 內部類,包含內部類的類稱為外部類。廣泛意義上的內部類一般包括四種:成員內部類,局部內部類,匿名內部類,靜態內部類 。
1.成員內部類
(1)該類像是外部類的一個成員,可以無條件的訪問外部類的所有成員屬性和成員方法(包括private成員和靜態成員);
(2)成員內部類擁有與外部類同名的成員變量時,會發生隱藏現象,即默認情況下訪問的是成員內部類中的成員。如果要訪問外部類中的成員,需要以下形式訪問:【外部類.this.成員變量 或 外部類.this.成員方法】;
(3)在外部類中如果要訪問成員內部類的成員,必須先創建一個成員內部類的對象,再通過指向這個對象的引用來訪問;
(4)成員內部類是依附外部類而存在的,也就是說,如果要創建成員內部類的對象,前提是必須存在一個外部類的對象;
(5)內部類可以擁有private訪問權限、protected訪問權限、public訪問權限及包訪問權限。如果成員內部類用private修飾,則只能在外部類的內部訪問;如果用public修飾,則任何地方都能訪問;如果用protected修飾,則只能在同一個包下或者繼承外部類的情況下訪問;如果是默認訪問權限,則只能在同一個包下訪問。外部類只能被public和包訪問兩種權限修飾。
2.局部內部類
(1)局部內部類是定義在一個方法或者一個作用域里面的類,它和成員內部類的區別在於局部內部類的訪問僅限於方法內或者該作用域內;
(2)局部內部類就像是方法里面的一個局部變量一樣,是不能有public、protected、private以及static修飾符的。
3.匿名內部類
(1)一般使用匿名內部類的方法來編寫事件監聽代碼;
(2)匿名內部類是不能有訪問修飾符和static修飾符的;
(3)匿名內部類是唯一一種沒有構造器的類;
(4)匿名內部類用於繼承其他類或是實現接口,並不需要增加額外的方法,只是對繼承方法的實現或是重寫。
4.內部靜態類
(1)靜態內部類是不需要依賴於外部類的,這點和類的靜態成員屬性有點類似;
(2)不能使用外部類的非static成員變量或者方法。
內部類(Inner Class)和靜態內部類(Static Nested Class)的區別:
內部類可以聲明public、protected、private等訪問限制,可以聲明 為abstract的供其他內部類或外部類繼承與擴展,或者聲明為static、final的,也可以實現特定的接口。外部類按常規的類訪問方式使用內部 類,唯一的差別是外部類可以訪問內部類的所有方法與屬性,包括私有方法與屬性。
(1)創建實例
OutClass.InnerClass obj = outClassInstance.new InnerClass(); //注意是外部類實例.new,內部類
AAA.StaticInner in = new AAA.StaticInner();//注意是外部類本身,靜態內部類
(2)內部類中的this
內 部類中的this與其他類一樣是指的本身。創建內部類對象時,它會與創造它的外圍對象有了某種聯系,於是能訪問外圍類的所有成員,不需任何特殊條件,可理 解為內部類鏈接到外部類。 用外部類創建內部類對象時,此內部類對象會秘密的捕獲一個指向外部類的引用,於是,可以通過這個引用來訪問外圍類的成員。
(3)外部類訪問內部類
內部類類似外部類的屬性,因此訪問內部類對象時總是需要一個創建好的外部類對象。內部類對象通過‘外部類名.this.xxx’的形式訪問外部類的屬性與方法。如:
System.out.println("Print in inner Outer.index=" + pouter.this.index);
System.out.println("Print in inner Inner.index=" + this.index);
(4)內部類向上轉型
內部類也可以和普通類一樣擁有向上轉型的特性。將內部類向上轉型為基類型,尤其是接口時,內部類就有了用武之地。如果內部類是private的,只可以被它的外部類問,從而完全隱藏實現的細節。
(5)方法內的類
方法內創建的類(注意方法中也能定義類),不能加訪問修飾符。另外,方法內部的類也不是在調用方法時才會創建的,它們一樣也被事先編譯了。
(6)靜態內部類
定義靜態內部類:在定義內部類的時候,可以在其前面加上一個權限修飾符static。此時這個內部類就變為了靜態內部類。
通常稱為嵌套類,當內部類是static時,意味着:
[1]要創建嵌套類的對象,並不需要其外圍類的對象;
[2]不能從嵌套類的對象中訪問非靜態的外圍類對象(不能夠從靜態內部類的對象中訪問外部類的非靜態成員);
嵌 套類與普通的內部類還有一個區別:普通內部類的字段與方法,只能放在類的外部層次上,所以普通的內部類不能有static數據和static字段, 也不能包含嵌套類。但是在嵌套類里可以包含所有這些東西。也就是說,在非靜態內部類中不可以聲明靜態成員,只有將某個內部類修飾為靜態類,然后才能夠在這 個類中定義靜態的成員變量與成員方法。
另外,在創建靜態內部類時不需要將靜態內部類的實例綁定在外部類的實例上。普通非靜態內部類的 對象是依附在外部類對象之中的,要在一個外部類中定義一個靜態的內部類,不需要利用關鍵字new來創建內部類的實例。靜態類和方法只屬於類本身,並不屬於 該類的對象,更不屬於其他外部類的對象。
(7)內部類標識符
每個類會產生一個.class文件,文件名即為類名。同樣,內部類也會產生這么一個.class文件,但是它的名稱卻不是內部類的類名,而是有着嚴格的限制:外圍類的名字,加上$,再加上內部類名字。
(8)為何要用內部類?
1. 內部類一般只為其外部類使用;
2. 內部類提供了某種進入外部類的窗戶;
3. 也是最吸引人的原因,每個內部類都能獨立地繼承一個接口,而無論外部類是否已經繼承了某個接口。因此,內部類使多重繼承的解決方案變得更加完整。
加深印象,參考一下:
package com.test.xml;
public class OutClassTest {
static int a;
int b;
public static void test() {
System.out.println("outer class static function");
}
public static void main(String[] args) {
OutClassTest oc = new OutClassTest();
// new一個外部類
OutClassTest oc1 = new OutClassTest();
// 通過外部類的對象new一個非靜態的內部類
OutClassTest.InnerClass no_static_inner = oc1.new InnerClass();
// 調用非靜態內部類的方法
System.out.println(no_static_inner.getKey());
// 調用靜態內部類的靜態變量
System.out.println(OutClassTest.InnerStaticClass.static_value);
// 不依賴於外部類實例,直接實例化內部靜態類
OutClassTest.InnerStaticClass inner = new OutClassTest.InnerStaticClass();
// 調用靜態內部類的非靜態方法
System.out.println(inner.getValue());
// 調用內部靜態類的靜態方法
System.out.println(OutClassTest.InnerStaticClass.getMessage());
}
private class InnerClass {
// 只有在靜態內部類中才能夠聲明或定義靜態成員
// private static String tt = "0";
private int flag = 0;
public InnerClass() {
// 三.非靜態內部類的非靜態成員可以訪問外部類的非靜態變量和靜態變量
System.out.println("InnerClass create a:" + a);
System.out.println("InnerClass create b:" + b);
System.out.println("InnerClass create flag:" + flag);
//
System.out.println("InnerClass call outer static function");
// 調用外部類的靜態方法
test();
