以前看<Java編程思想>的時候,看到過嵌套類跟內部類的區別,不過后來就把它們的概念給忘了吧。昨天在看<數據結構與算法分析(Java語言版)>的時候,又遇到了這個概念,當時就很大的疑惑:嵌套類跟內部類有什么區別?只有是否有關鍵字static的區別嗎?
所以今天找了個時間查了一下兩者的詳細區別,總結在這篇博客中,既方便自己的復習和學習,也啟示他人吧。
1,概念:
定義在一個類內部的類,叫作“嵌套類”。嵌套類分為兩種:static的和非static的。后者又有一個專門的名字,叫作“內部類”。所以從概念可以看出,嵌套類跟內部類是所屬關系,后者包含於前者。示例代碼如下:

1 class OuterClass { 2 ... 3 static class StaticNestedClass { 4 ... 5 } 6 class InnerClass { 7 ... 8 } 9 }
同時,嵌套類是其所在類的成員。內部類可以訪問所在類的所有成員,即使該成員是private的。而static嵌套類則不得訪問所在類的成員。同時,嵌套類,static和非static的,都可以被聲明為private、public、protected和default的。
2,為什么要使用嵌套類?
好處應該都比較文本化吧,以后在使用的過程中去理解和體會吧:對只在一個地方使用的類進行邏輯上的分組;增加了封裝性;易於閱讀和維護。
3,static嵌套類:
因為static嵌套類不能直接訪問所在類的非static成員變量和方法,所以static嵌套類必須通過綁定所在類的實例來進行訪問。而對於所在類的靜態成員和方法包括private、protected和public的,可以訪問。因為它也有static修飾。
static嵌套類通過寫出封裝的類名來進行實例化和訪問其內部成員:

1 OuterClass.StaticNestedClass nestedObject = 2 new OuterClass.StaticNestedClass();
4,內部類:
因為內部類是所在類的成員,所以它可以訪問所在類的任意變量和方法,但是它本身卻不能定義任何static的變量或方法。
同時,內部類的實例化方式也與static嵌套類有所不同:

1 OuterClass outerObject=new OuterClass(); 2 OuterClass.InnerClass innerObject = outerObject.new InnerClass();
static嵌套類與non-static嵌套類,在形式上只有是否含有static關鍵字的區別,但是JVM在初始化時兩者還是有差別的:差別就是后者在實例化時會自動地與外圍實例建立一種聯系,且這種聯系不得修改。JVM在實例化non-static嵌套類時會生成一個指向外圍實例的對象引用(this),保存這種引用將會消耗時間和空間,同時,在外圍實例滿足垃圾回收的條件時仍然得以留存。
5,內部類的分類:
以前曾經接觸過內部類的分類,這里一並總結一下:
以前的所謂的一些面試寶典里面差不多都是將內部類分為四個種類:
靜態內部類(既static嵌套類)、成員內部類(既上述內部類)、局部內部類和匿名內部類。前兩者都已經介紹過了,下面專門看一下后面兩者。
5.1,局部內部類:
定義在方法內部的類叫作“局部內部類”。它的作用域僅限於方法作用域內,只能在方法的作用域內定義和實例化,是用處最小的類類型。和局部變量一樣,它不能被修飾為private, public, protected和static的,並且只能訪問方法內部定義的final變量。

1 class LocalInner 2 { 3 int a = 1; 4 5 public void doSomething() 6 { 7 int b = 2; 8 final int c = 3; 9 // 定義一個局部內部類 10 class Inner3 11 { 12 public void test() 13 { 14 System.out.println("Hello World"); 15 System.out.println(a); 16 17 // 不可以訪問非final的局部變量 18 // error: Cannot refer to a non-final variable b inside an inner 19 // class defined in a different method 20 // System.out.println(b); 21 22 // 可以訪問final變量 23 System.out.println(c); 24 } 25 } 26 27 // 創建局部內部類的實例並調用方法 28 new Inner3().test(); 29 } 30 } 31 32 public class LocalInnerClassTest 33 { 34 public static void main(String[] args) 35 { 36 // 創建外部類對象 37 LocalInner inner = new LocalInner(); 38 // 調用外部類的方法 39 inner.doSomething(); 40 } 41 42 }
5.2,匿名內部類:
顧名思義,匿名內部類就是沒有名字的局部類。它不使用關鍵字class, extends, implements以及構造函數。
它通常作為方法的一個參數傳入,比如在android開發中對一個Button添加一個OnClickListener監聽器。
匿名內部類隱匿的繼承了一個父類或者實現了一個接口。比如:

1 mUiHandler.post(new Runnable{ 2 @override 3 public void run(){ 4 // 5 } 6 7 }); 8 9 AsyncClient.get(url, new JsonHttpResponseHandler() { 10 @Override 11 public void onSuccess(int statusCode, Header[] headers, 12 JSONObject response) { 13 // TODO Auto-generated method stub 14 super.onSuccess(statusCode, headers, response);}} );
內部類通過將相關的類組織在一直,從而降低了命名空間的復雜性。
6,內部類的序列化問題。
對任何種類內部類(包括局部內部類和匿名內部類)的序列化都是不被鼓勵的。因為java編譯器在對內部類進行編譯的時候,將進行“合成構造”。合成構造使得java編譯器實現了java的新特性,但是卻沒有對JVM做出相應的改變。然而,不同的java編譯器對合成構造是有差別的,因而,如果對內部類進行了序列化,將使得不同的JRE實現中存在兼容性問題。
本文是在參考了大量他人的勞動成果之上的而寫成的,主要的參考文獻有:
http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html;
http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html。