外部類和內部類其實是2個類,先加載外部類在加載內部類
在Java中內部類主要分為成員內部類(非靜態內部類、靜態內部類)匿名內部類、局部內部類。成員內部類可以用public、private、protected、default任意進行修飾。
非靜態內部類(外部類里使用非靜態內部類和平時使用其它類沒什么不同)
-
非靜態內部類 可以直接訪問外部類的成員但是外部類不能直接訪問非靜態內部類成員,可以通過創建靜態內部類的對象來訪問。
-
非靜態內部類必須寄存在一個外部類對象里。因此,如果有一個非靜態內部類對象,那么一定存在對應的外部類對象。非靜態內部類對象單獨屬於外部類的某個對象
-
非靜態內部類不能有靜態方法、靜態屬性和靜態初始化塊(就是不能有static的存在)(解釋:非static的內部類,在外部類加載的時候,並不會加載它,所以它里面不能有靜態變量或者靜態方法。1、static類型的屬性和方法,在類加載的時候就會存在於內存中。2、要使用某個類的static屬性或者方法,那么這個類必須要加載到jvm中。基於以上兩點,可以看出,如果一個非static的內部類如果具有static的屬性或者方法,那么就會出現一種情況:內部類未加載,但是卻試圖在內存中創建static的屬性和方法,這當然是錯誤的。原因:類還不存在,但卻希望操作它的屬性和方法。)
-
外部類的靜態方法、靜態代碼塊不能訪問非靜態內部類,包括不能使用非靜態內部類定義變量、創建實例
1 package com.testInner; 2 public class TestInner { 3 public static void main(String[] args) { 4 Outer.Inner inner = new Outer().new Inner();//定義一個內部類的對象,內部類對象是依賴外部類對象的,所以得這么創建 5 inner.show(); 6 } 7 } 8 //定義外部類 9 class Outer{ 10 private int age=90; 11 public void run() { 12 System.out.println("Run"); 13 } 14 //定義內部類 15 class Inner{ 16 private int age=10; 17 public void show() { 18 System.out.println("Inner's age is:"+age);//10 19 System.out.println("Outer's age is:"+Outer.this.age);//90 20 int age = 5; 21 System.out.println("Local variable's age is:"+age);//5 22 23 } 24 } 25 }
靜態內部類:
-
當一個靜態內部類對象存在,並不一定存在對應的外部類對象。因此,靜態內部類的實例方法不能直接訪問外部類的實例方法。
-
靜態內部類看作外部類的一個靜態成員。因此,外部類的方法中可以通過“靜態內部類.名字”的方式訪問靜態內部類的靜態成員,通過new靜態內部類()訪問靜態內部類的實例
1 package com.testInner; 2 public class TestInner { 3 public static void main(String[] args) { 4 Outer.Inner inner = new Outer().new Inner();//錯誤, 5 修正:Outer.Inner inner = new Outer.Inner(); 6 inner.show(); 7 } 8 } 9 //定義外部類 10 class Outer{ 11 private int age=90; 12 public void run() { 13 System.out.println("Run"); 14 } 15 //定義內部類 16 static class Inner{ 17 private static int age=10; 18 public void show() { 19 System.out.println("Inner's age is:"+age); 20 System.out.println("Outer's age is:"+Outer.this.age);//錯誤,不能訪問外部類的非static成員 21 int age = 5; 22 System.out.println("Local variable's age is:"+age); 23 24 } 25 } 26 }
匿名內部類:適合那種只需要使用一次的類,比如鍵盤監聽操作等等
語法:
new 父類構造器(實參類表)/實現接口 (){ //匿名內部類的類體 }
Example:
1 package com.testanonymousclass; 2 public class TestAnonymousClass { 3 4 public void a(A a) { 5 System.out.println("#################"); 6 a.aa(); 7 } 8 9 10 public static void main(String args[]) { 11 TestAnonymousClass t = new TestAnonymousClass(); 12 t.a(new A() {//有個沒名的類實現了A接口它的類體中實現了aa方法,並且這個沒名的類通過new了個對象傳給了TestAnonymousClass的a方法 13 public void aa() { 14 System.out.println("I'm the anonymousclass's function."); 15 } 16 }); 17 } 18 } 19 interface A{ 20 public void aa(); 21 }
此處的A是接口,而我們卻new了A,那不就是直接實例化接口啦?其實不然,此處代碼的意思就是new了一個實現A接口的匿名內部類,然后new得到匿名內部類的對象再向上轉型為它實現的接口的類型(原始類型,這里實現A接口的就是該匿名類)。
局部內部類:在方法體中定義一個類,該類的作用域只在這個方法體中。
1 public class Test2{ 2 public void show(){ 3 class Inner{ 4 public void fun(){ 5 System.out.println("HelloWorld"); 6 } 7 } 8 new Inner().fun(); 9 } 10 public static void main(String args[]){ 11 new Test2().show(); 12 } 13 }