定義在一個類內部的類,稱爲內部類(累不累),以下:java
public class A { private int c = 1; public class C { public void test() { System.out.println("c:" + c); } } }
C稱爲A的內部類,簡稱內部類this
A稱爲C的外部類,簡稱外部類code
並且內部類能訪問外部類的成員(靜態成員、實例成員),固然有一些限制,限制以下對象
按照內部類的聲明方式,分爲4種內部類:blog
靜態內部類繼承
像類的靜態成員同樣聲明的類,就稱呼爲「靜態內部類」接口
public class A { private static String b = "b"; private int c = 1; // B是A的靜態內部類 public static class B { public void test() { System.out.println(b); } } }
靜態內部類,只能訪問外部類的靜態成員(方法和變量),而且能夠像類的成員同樣使用修飾符(public/protected/private);編譯器
建立靜態內部類對象的方式:A.B b = new A.B()
;編譯
成員內部類class
新類的實例成員(未加static修飾)聲明的類,稱爲「成員內部類」
public class A { private static String b = "b"; private int c = 1; // C是A的成員內部類 public class C { public void test() { System.out.println(c); System.out.println(b); } } }
成員內部類,訪問外部類的一切(靜態,仍是實例),就像成員方法同樣,而且能夠像類的成員同樣使用修飾符(public/protected/private)
建立成員內部類對象的方式:
A a = new A(); A.C c = a.new C();
方法內部類
在一個代碼塊聲明的類稱爲方法內部類,代碼塊包括(方法內、靜態代碼塊內、實例代碼塊內)
public class A { private static String b; private int c; // 成員方法 public void test() { final int d = 1; // 方法內部類 class D { public void test() { // 訪問靜態變量 System.out.println(b); // 訪問實例變量 System.out.println(c); // 訪問方法final類型的局部變量 System.out.println(d); } } } }
方法內部類,和它所在的方法(代碼塊),具備相同的訪問能力,若是上面代碼是在static方法中聲明的,那麼內部類D不能訪問c變量。
jdk1.8 方法內部類,可以訪問非final類型的局部變量,本質至關有在內部類D內保存了副本
匿名內部類
匿名內部類也就是沒有名字的內部類
正由於沒有名字,因此匿名內部類只能使用一次,它一般用來簡化代碼編寫
但使用匿名內部類還有個前提條件:必須繼承一個父類或實現一個接口
內部類的語法頗爲奇怪,咱們來看看以下代碼,編譯後的字節碼文件!
public class A { private static String b = "b"; private int c = 1; // 靜態內部類 public static class B { public void b() { System.out.println(b); } } // 成員內部類 class C { public void c() { System.out.println(c); } } }
內部類會被編譯成單獨的class文件,那意味JVM解釋執行class文件時類「B」和類A是獨立的,由此能夠見內部類也是一種語法糖!
對於JVM來講,類A的private b和c 成員,怎麼能分別被類B和類C訪問到的了!
用javap命令反編譯類A.class來看看:
祕密就來自,編譯器爲外部類生的兩個靜態訪問方法,Stinrg access$000()
返回b變量的值,int access$100(A a)
返回a對象的c成員變量值;
而在靜態內部類B中,編譯器將訪問靜態變量b的地方替換爲如上方法:
// 靜態內部類 public static class A$B { public void b() { System.out.println(A.access$000()); } }
在成員內部類C中,原理也是如此,不過增長了更多的東西,反編譯A$C.class:
final A $this
;System.out.println(A.access$100($this));
你必定會好奇成員構造方法中的外部類對象的參數從哪裏傳入的!看看咱們是怎麼聲明內部類的對象的
A a = new A(); A.C c = a.new C();
將會被編譯器替換成:
A a = new A(); A$C c = new A$C(a);
兩個類之間緊密聯繫時,可使用內部類: