一、 內部類概念
一個類定義在另一個類的內部,這個類就叫做內部類。
代碼示例:
public class TestClass {
/*內部類,可以用private/public/protected修飾*/
private class InnerClass{
}
public static void main(String[] args) {
}
}
內部類作為外部類的一個成員,並且依附於外部類而存在的。內部類可為靜態,可用protected和private修飾(而外部類只能使用public和缺省的包訪問權限)。內部類主要有以下幾類:成員內部類、局部內部類、靜態內部類、匿名內部類。
內部類生成的class文件名稱是外部類類名加上”$”再加上內部類類名,如上內部類就是OuterClass$InnerClass.class。
除匿名內部類之外,其他的內部類都是在編譯時直接生成而不是在調用時才生成。匿名內部類由於沒有類名因此只有在運行時才會生成,而且只能創建一個實例。
為什麼需要內部類?典型的情況是,內部類繼承自某個類或實現某個接口,內部類的代碼操作創建其的外圍類的對象。所以你可以認為內部類提供了某種進入其外圍類的窗口。
使用內部類最吸引人的原因是:每個內部類都能獨立地繼承自一個(接口的)實現,所以無論外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。如果沒有內部類提供的可以繼承多個具體的或抽象的類的能力,一些設計與編程問題就很難解決。從這個角度看,內部類使得多重繼承的解決方案變得完整。接口解決了部分問題,而內部類有效地實現了“多重繼承”。
二、 內部類的定義位置
正如上述所列的幾種內部類:成員內部類、局部內部類、靜態內部類、匿名內部類,這幾種內部類的區分正是由於定義的位置不同。
成員內部類:定義在外部類的內部,非方法內,相當於外部類的一個成員變量。
局部內部類:定義在外部類的方法中,可以使靜態方法和普通方法,注意局部內部類的修飾符只能是abstract和final。
靜態內部類:又叫嵌套類,是定義位置同成員內部類,但是使用static修飾符修飾。靜態內部類相當於外部類的靜態成員變量(後面介紹)。
匿名內部類:主要出現在方法內,沒有類名,當然也就沒有構造方法。(後面介紹)
代碼示例:
public class TestClass {
/* 成員內部類,可以用private/public/protected修飾,不可以定義靜態成員變量 */
protected class InnerClass01 {
private String myName = "Vicky" ;
}
/* 靜態內部類,可以用private/public/protected修飾,可以有靜態變量以及靜態方法 */
public static class StaticInnerClass {
public static String myName = "Vicky";
public static void main(String[] args) {
}
}
public void method() {
/* 普通方法內的局部內部類,只能使用abstract/final修飾,可以定義靜態成員變量 */
abstract class InnerClass02 {
}
}
public static void method02() {
/* 靜態方法內的局部內部類,只能使用abstract/final修飾,可以重名 */
final class InnerClass01 {
}
}
public static void main(String[] args) {
/*匿名內部類*/
Thread th = new Thread(new Runnable(){
@Override
public void run() {
}
}) ;
}
}
注意:非靜態內部類(成員內部類和局部內部類)外其他類型的內部類都不能定義靜態成員,包括變量以及方法;靜態內部類可以有靜態方法(包括main())和靜態變量。匿名內部類由於沒有類名,故也沒有構造方法,但可以非靜態定義變量以及方法。
三、 普通內部類(成員內部類和局部內部類)的實例化方式
內部類作為定義在外部類的成員變量,如同變量的使用一樣,需要一個外部類的實例來調用,除靜態內部類外。
注意在不同的位置實例化內部類的方式有不同的實例化方式。
代碼示例:
public class OuterClass {
/* 外部類的變量可以使用內部類,使用內部類類名和new就可以實例化,同一般類的實例化 */
private InnerClass innerVar = new InnerClass();
/* 成員內部類,可以用private/public/protected修飾,不可以定義靜態成員變量 */
protected class InnerClass {
private String myName = "Vicky";
}
public void method() {
/* 普通方法內直接使用內部類類名和new就可以實例化,同一般類的實例化 */
InnerClass inner01 = new InnerClass();
/* 普通方法內的局部內部類,只能使用abstract/final修飾,可以定義靜態成員變量 */
final class InnerClass02 {
}
/* 方法內的局部內部類,只能在方法內部使用,就如在方法內定義的變量只能在方法內部使用一樣*/
InnerClass02 inner = new InnerClass02() ;
}
public static void method02() {
/* 顯然靜態方法中不能使用非靜態內部類 */
}
public static void main(String[] args) {
/* 我們知道main()方法和它所在的類沒有任何關系,因此在main()方法中實例化內部類就同在其他類中一樣,這樣方便些 */
// 首先實例化外部類,得到一個外部類對象
OuterClass outer = new OuterClass();
// 通過外部類的對象實例化內部類
OuterClass.InnerClass inner = outer.new InnerClass();
}
}
我們可以看出定義在方法內的局部內部類只能在方法內部使用,就如定義在方法內部的變量一樣。
四、 普通內部類(成員內部類和局部內部類)使用外部類的域
普通內部類可以直接訪問外部類的所有域(包括private修飾的成員),如變量、方法等(但是有些地方需要注意)。普通內部類在實例化時會被自動添加一個指向外部類的引用,實際上是編譯器在編譯時為內部類構造了一個帶有外部類類型參數的構造方法,如
public InnerClass(OuterClass outer){
}
通過這個構造方法普通內部類就可以得到外部類的引用也就可以使用外部類的所有域。普通內部類(成員內部類/局部內部類)可以直接使用外部類包括靜態成員變量在內的所有域(包括private修飾的)。靜態內部類不是這樣(後面介紹)。
代碼示例:
public class OuterClass {
private String myName = "Vicky";
private static int myAge = 21;
public void method() {
System.out.println("you are invoking outer class's common method ...");
}
public static void staticMethod() {
System.out.println("you are invoking outer class's static method ...");
}
public void method01(){
/* 局部類變量 */
final class InnerClass {
/* 內部類變量使用外部類普通變量 */
private String inner_myName = myName;
/* 內部類變量使用外部類靜態變量 */
private int inner_myAge = myAge;
public void inner_method() {
System.out.println("myName--" + inner_myName + ";myAge--"
+ inner_myAge);
/* 內部類使用外部類普通方法 */
method();
/* 內部類使用外部類靜態方法 */
staticMethod();
}
}
}
/* 成員內部類*/
private class InnerClass {
/* 內部類變量使用外部類普通變量 */
private String inner_myName = myName;
/* 內部類變量使用外部類靜態變量 */
private int inner_myAge = myAge;
public void inner_method() {
System.out.println("myName--" + inner_myName + ";myAge--"
+ inner_myAge);
/* 內部類使用外部類普通方法 */
method();
/* 內部類使用外部類靜態方法 */
staticMethod();
}
}
public static void main(String[] args) {
OuterClass outer = new OuterClass() ;
OuterClass.InnerClass inner = outer.new InnerClass() ;
inner.inner_method() ;
}
}
成員內部類和局部內部類在使用外部類的域時是一樣的,可以直接調用。