Java中的嵌套類和內部類


以前看<Java編程思想>的時候,看到過嵌套類跟內部類的區別,不過后來就把它們的概念給忘了吧。昨天在看<數據結構與算法分析(Java語言版)>的時候,又遇到了這個概念,當時就很大的疑惑:嵌套類跟內部類有什么區別?只有是否有關鍵字static的區別嗎?

所以今天找了個時間查了一下兩者的詳細區別,總結在這篇博客中,既方便自己的復習和學習,也啟示他人吧。

1,概念:

定義在一個類內部的類,叫作“嵌套類”。嵌套類分為兩種:static的和非static的。后者又有一個專門的名字,叫作“內部類”。所以從概念可以看出,嵌套類跟內部類是所屬關系,后者包含於前者。示例代碼如下:

1 class OuterClass {
2     ...
3     static class StaticNestedClass {
4         ...
5     }
6     class InnerClass {
7         ...
8     }
9 }
View Code

同時,嵌套類是其所在類的成員。內部類可以訪問所在類的所有成員,即使該成員是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();
View Code

4,內部類:

因為內部類是所在類的成員,所以它可以訪問所在類的任意變量和方法,但是它本身卻不能定義任何static的變量或方法。

同時,內部類的實例化方式也與static嵌套類有所不同:

1 OuterClass outerObject=new OuterClass();
2 OuterClass.InnerClass innerObject = outerObject.new InnerClass();
View Code

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 }
View Code

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);}} );
View Code

內部類通過將相關的類組織在一直,從而降低了命名空間的復雜性。

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。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM