在java中允許在類的內部再定義一個類,這個定義在類內部的類稱之為內部類,包含內部類的類稱之為外部類。內部類可以方便的訪問外部類的私有屬性和方法,可以把內部類定義為private以實現對外部的完全封裝,同時內部類也可以讓類的結構層次更加的清晰,代碼也比較的簡潔。
java中的內部類只是java編譯器的概念,對於java的虛擬機而言,它是沒有java內部類的概念的,也就是說java中的內部類最后也會被編譯成一個獨立的class文件。在java中有四中常見的內部類,它們分別是:靜態內部類、成員內部類、方法內部類、匿名內部類。
1.靜態內部類
靜態內部類的定義方式和定義靜態方法的方式一樣只是把關鍵字換成class即可。
public class StaticOutter { private static Integer outterNum = 1; private static void outStatic(){ System.out.println("run out static"); } public static class StaticInner{ public void testStaticInner(){ System.out.println("調用外部類的靜態方法"); outStatic(); System.out.println("調用外部類的靜態屬性"); System.out.println(outterNum); } } }
靜態內部類可以直接訪問外部的靜態屬性和方法,但是不可訪問外部類的實例屬性和方法。上面我們介紹其實內部類只是java編譯器的概念真正在java執行時會產生兩個class文件,可是我們知道類的私有屬性在類外是無法訪問的那么java是怎么實現內部類訪問外部類的私有屬性和方法的呢?查看編譯后的代碼發現,java生成了兩個class文件,一個叫StaticOutter.class,一個叫StaticOutter$StaticInner.class,反編譯class文件發現內部類訪問外部類的私有靜態屬性,java編譯器會自動為StaticOutter生成一個非私有的訪問方法access$0,它返回StaticOutter類的私有屬性。
public class StaticOutter$StaticInner { public void testStaticInner() { System.out.println("調用外部類的靜態方法"); StaticOutter.access$0(); System.out.println("調用外部類的靜態屬性"); System.out.println(StaticOutter.access$1()); } }
2.成員內部類
成員內部類的定義方式基本與靜態內部類相同只是去掉static修飾符即可。
public class Outter { private Integer outterNum = 1; private void outterMethod(){ System.out.println("運行外部方法......"); } public class Inner{ public void innerMethod(){ System.out.println("outterNum:"+outterNum); System.out.println("運行outter的方法"); outterMethod(); } } }
在內部類Inner中除了可以訪問外部類的靜態方法和屬性還可以訪問外部類的實例屬性和方法。其中在內部類還可以通過Outter.this.xxx來調用Outter類中的實例屬性,這樣調用主要是在重名的情況下使用,一般情況下可以省略Outter.this。成員內部類和靜態內部類不同,在成員內部類中不可以定義靜態變量和靜態方法。這個我的理解就是因為成員內部類依托於與外部類的實例,正如在實例方法中無法定義靜態變量,這里可以把成員內部類看成一個比較特殊的”實例方法“。
3.方法內部類
在方法的內部定義一個類稱之為方法內部類。
public class MethodOutter { private Integer outter = 10; public void testMethod(Integer param){ String local = "hello"; class MethodInner{ public void innerMethod(){ System.out.println("MethodOutter outter:"+outter); System.out.println("param:"+param); System.out.println("local:"+local); } } MethodInner inner = new MethodInner(); inner.innerMethod(); } public static void main(String[] args) { MethodOutter out = new MethodOutter(); out.testMethod(1); } }
方法內部類只能在定義的方法中使用,其中在實例方法中定義的內部類可以直接訪問外部類的實例方法和屬性但是不能訪問外部類定義的靜態方法和靜態屬性。如果在靜態方法中定義則只可以訪問外部類的靜態方法和靜態屬性。在方法內部類中可以調用方法的形式參數和局部變量,但是注意這些變量具有final的語義,如果在內部類中修改導致編譯異常。
4.匿名內部類
匿名內部類和前面介紹的內部類不同,匿名內部類沒有單獨定義類而是通過new后面是父類或者接口時創建的。
public interface TestInteface { public void show(String param); } public class AnonymousTest { public void test(){ new TestInteface() { @Override public void show(String param) { System.out.println(param); } }; } }
匿名內部類只能使用一次,它沒有名字,沒有構造方法但是它可以根據參數調用父類的構造方法。和方法內部類一樣,匿名內部類可以訪問外部類的變量和方法,也可以訪問方法中的局部變量和參數,但是這些變量依然具有final的語義。
內部類的使用可以讓我們的代碼具有良好的封裝性,代碼的結構也會變得更加的清晰。