以前看<Java編程思想>的時候,看到過嵌套類跟內部類的區別,不過後來就把它們的概念給忘了吧。昨天在看<數據結構與算法分析(Java語言版)>的時候,又遇到了這個概念,當時就很大的疑惑:嵌套類跟內部類有什麼區別?只有是否有關鍵字static的區別嗎?
所以今天找了個時間查了一下兩者的詳細區別,總結在這篇博客中,既方便自己的復習和學習,也啟示他人吧。
1,概念:
定義在一個類內部的類,叫作“嵌套類”。嵌套類分為兩種:static的和非static的。後者又有一個專門的名字,叫作“內部類”。所以從概念可以看出,嵌套類跟內部類是所屬關系,後者包含於前者。示例代碼如下:
class OuterClass { ... static class StaticNestedClass { ... } class InnerClass { ... } }
同時,嵌套類是其所在類的成員。內部類可以訪問所在類的所有成員,即使該成員是private的。而static嵌套類則不得訪問所在類的成員。同時,嵌套類,static和非static的,都可以被聲明為private、public、protected和default的。
2,為什麼要使用嵌套類?
好處應該都比較文本化吧,以後在使用的過程中去理解和體會吧:對只在一個地方使用的類進行邏輯上的分組;增加了封裝性;易於閱讀和維護。
3,static嵌套類:
因為static嵌套類不能直接訪問所在類的非static成員變量和方法,所以static嵌套類必須通過綁定所在類的實例來進行訪問。而對於所在類的靜態成員和方法包括private、protected和public的,可以訪問。因為它也有static修飾。
static嵌套類通過寫出封裝的類名來進行實例化和訪問其內部成員:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
4,內部類:
因為內部類是所在類的成員,所以它可以訪問所在類的任意變量和方法,但是它本身卻不能定義任何static的變量或方法。
同時,內部類的實例化方式也與static嵌套類有所不同:
OuterClass outerObject=new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass();
5,內部類的分類:
以前曾經接觸過內部類的分類,這裡一並總結一下:
以前的所謂的一些面試寶典裡面差不多都是將內部類分為四個種類:
靜態內部類(既static嵌套類)、成員內部類(既上述內部類)、局部內部類和匿名內部類。前兩者都已經介紹過了,下面專門看一下後面兩者。
5.1,局部內部類:
定義在方法內部的類叫作“局部內部類”。它的作用域僅限於方法作用域內,只能在方法的作用域內定義和實例化,是用處最小的類類型。和局部變量一樣,它不能被修飾為private, public, protected和static的,並且只能訪問方法內部定義的final變量。
class LocalInner { int a = 1; public void doSomething() { int b = 2; final int c = 3; // 定義一個局部內部類 class Inner3 { public void test() { System.out.println("Hello World"); System.out.println(a); // 不可以訪問非final的局部變量 // error: Cannot refer to a non-final variable b inside an inner // class defined in a different method // System.out.println(b); // 可以訪問final變量 System.out.println(c); } } // 創建局部內部類的實例並調用方法 new Inner3().test(); } } public class LocalInnerClassTest { public static void main(String[] args) { // 創建外部類對象 LocalInner inner = new LocalInner(); // 調用外部類的方法 inner.doSomething(); } }
5.2,匿名內部類:
顧名思義,匿名內部類就是沒有名字的局部類。它不使用關鍵字class, extends, implements以及構造函數。
它通常作為方法的一個參數傳入,比如在android開發中對一個Button添加一個OnClickListener監聽器。
匿名內部類隱匿的繼承了一個父類或者實現了一個接口。比如:
mUiHandler.post(new Runnable{ @override public void run(){ // } }); AsyncClient.get(url, new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject response) { // TODO Auto-generated method stub super.onSuccess(statusCode, headers, response);}} );
內部類通過將相關的類組織在一直,從而降低了命名空間的復雜性。
6,內部類的序列化問題。
對任何種類內部類(包括局部內部類和匿名內部類)的序列化都是不被鼓勵的。因為java編譯器在對內部類進行編譯的時候,將進行“合成構造”。合成構造使得java編譯器實現了java的新特性,但是卻沒有對JVM做出相應的改變。然而,不同的java編譯器對合成構造是有差別的,因而,如果對內部類進行了序列化,將使得不同的JRE實現中存在兼容性問題。
查看本欄目