1. 程式人生 > >深入理解java巢狀類和內部類、匿名類

深入理解java巢狀類和內部類、匿名類



四、在外部類中定義內部類

匿名類就是沒有名字的內部類,是內部類的一種特殊情況。?????????  這句話對嗎???

前端時間在寫.net專案中,一直錯將.cs裡的兩個class當作內部類,原來是一個檔案裡的兩個類而已,這讓我想起了Java中的內部類,比較內部類,那麼還有兩個類,那就是匿名類和匿名內部類。今天我想就Java中的這三種類進行個比較。

我們知道在Java語言規範中可以做很多事,例如一個類或一個介面中可以宣告一個類或介面,在一個方法中可以宣告一個類,類與介面宣告可以巢狀任意深度等。

匿名類:

      1、new <類或介面><類的主體>,匿名類的宣告是在編譯時進行的,例項化是在執行時進行的,所以在for迴圈中一個new語句會建立相同匿名類的幾個例項,而不是建立幾個不同匿名類的一個例項。

      2、如果要執行的物件需要一個物件,但卻不值得建立全新的物件(可能是因為該物件只在一個方法內部使用),在這個時候使用匿名類就會非常合適,所以說,匿名類一般會在swing程式中快速建立事件處理程式。

Java程式碼  收藏程式碼
  1. firstButton.addActionListener(new ActionListener() {  
  2.         @Override  
  3.         public void actionPerformed(ActionEvent e) {  
  4.             getTxtValue().setText("第一個按鈕觸發的事件!");  
  5.         }  
  6.     });   

       3、從技術上說,匿名類可以被看作非靜態的內部類,所以他們具有方法內部宣告的非靜態內部類相同的許可權和限制。

內部類:

內部類顧名思義就是在一個類的內部還有一個類

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo {  
  8.     public static void main(String[] args) {  
  9.         new Outer().fun();  
  10.     }  
  11. }  
  12. class Outer {  
  13.     private String name = "Hello 內部類";  
  14.     class Inner {  
  15.         public void print() {  
  16.             System.out.println("name = " + name);  
  17.         }  
  18.     };  
  19.     public void fun() {  
  20.         new Inner().print();  
  21.     }  
  22. }  

 內部類生成的.class檔名為:Outer$Inner.class,從上面的結構發現內部類的的缺點是“結構非常的混亂”。

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo02 {  
  8.     public static void main(String[] args) {  
  9.         new Outer02().fun();  
  10.     }  
  11. }  
  12. class Outer02 {  
  13.     private String name = "Hello 內部類";  
  14.     public void fun() {  
  15.         new Inner02(this).print();  
  16.     }  
  17.     public String getName() {  
  18.         return this.name;  
  19.     }  
  20. };  
  21. class Inner02 {  
  22.     private Outer02 out;  
  23.     public Inner02(Outer02 out) {  
  24.         this.out = out;  
  25.     }  
  26.     public void print() {  
  27.         System.out.println("name = " + this.out.getName());  
  28.     }  
  29. };  

 從上可以看出內部類的優點是“可以方便的訪問外部類中的私有成員”;

如果要在外部直接使用內部類的例項化物件:

      外部類.內部類 內部類物件 = 外部類例項.new 內部類例項();

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang  2012-1-11 
  4.  * 
  5.  *  Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo03 {  
  8.     public static void main(String[] args) {  
  9.         Outer03 out = new Outer03();//外部類例項  
  10.         Outer03.Inner inner = out.new Inner();//例項化內部類物件  
  11.         inner.print();  
  12.     }  
  13. }  
  14. class Outer03{  
  15.     private String name = "Hello 內部類";  
  16.     class Inner {  
  17.         public void print() {  
  18.             System.out.println("name = " + name);  
  19.         }  
  20.     }  
  21. }  

 一個內部類如果使用static關鍵字宣告的話,則此內部類就將成為外部類,可以直接通過外部類.內部類的形式訪問

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo04 {  
  8.     public static void main(String[] args) {  
  9.         Outer04.Inner inner = new Outer04.Inner();// 例項化內部類物件  
  10.         inner.print();  
  11.     }  
  12. }  
  13. class Outer04 {  
  14.     private static String name = "Hello 內部類";  
  15.     static class Inner {  
  16.         public void print() {  
  17.             System.out.println("name = " + name);  
  18.         }  
  19.     }  
  20. }  

 內部類可以在任意的地方使用,例如方法中宣告

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo05 {  
  8.     public static void main(String[] args) {  
  9.         new Outer05().fun();  
  10.     }  
  11. }  
  12. class Outer05 {  
  13.     private static String name = "Hello 內部類";  
  14.     public void fun() {  
  15.         class Inner {  
  16.             public void print() {  
  17.                 System.out.println("name = " + name);  
  18.             }  
  19.         }  
  20.         new Inner().print();  
  21.     }  
  22. }  

 在方法中定義的內部類,可以直接訪問外部類中的各個成員,但是如果要訪問方法中的引數,則需要在引數上加上final關鍵字宣告;

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class InnerClassDemo06 {  
  8.     public static void main(String[] args) {  
  9.         new Outer06().fun(20);  
  10.     }  
  11. }  
  12. class Outer06 {  
  13.     private static String name = "Hello 內部類";  
  14.     public void fun(final int temp) {  
  15.         class Inner {  
  16.             public void print() {  
  17.                 System.out.println("temp = " + temp);  
  18.                 System.out.println("name = " + name);  
  19.             }  
  20.         }  
  21.         new Inner().print();  
  22.     }  
  23. }  

 匿名類與內部的聯絡與區別:

按所在位置可以分為兩大類:

      1、在類的方法中

                     特點:

                              a、可以訪問宿主類的所有元素 ;

                              b、儲存宿主類物件的引用,建立物件時必須有宿主類物件;

                              c、 不能有靜態資料;

繼續劃分:

                             A、本地內部類;

                             B、匿名內部類

 兩者的區別在於本地內部類有構造方法,而匿名內部類只能例項初始化;

      2、在類或介面作用域中;

                     繼續劃分:

                            A、普通內部類

                            B、靜態內部類

匿名內部類:

匿名內部類是在抽象類和介面的基礎之上發展起來的。

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class NoNameClass01 {  
  8.     public static void main(String[] args) {  
  9.         new X().fun2();  
  10.     }  
  11. }  
  12. interface A {  
  13.     public void fun();  
  14. }  
  15. class B implements A {  
  16.     public void fun() {  
  17.         System.out.println("Hello 準備匿名內部類");  
  18.     }  
  19. }  
  20. class X {  
  21.     public void fun1(A a) {  
  22.         a.fun();  
  23.     }  
  24.     public void fun2() {  
  25.         this.fun1(new B());  
  26.     }  
  27. }  

 通過上面的Demo,如果現在假設B類只使用一次,那麼還有必要將其定義成一個單獨的類麼?

 呵呵,此時就可以使用匿名內部類:

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class NoNameClass02 {  
  8.     public static void main(String[] args) {  
  9.         new XX().fun2();  
  10.     }  
  11. }  
  12. interface AA {  
  13.     public void fun();  
  14. }  
  15. class XX {  
  16.     public void fun1(AA a) {  
  17.         a.fun();  
  18.     }  
  19.     public void fun2() {  
  20.         this.fun1(new AA() {  
  21.             public void fun() {  
  22.                 System.out.println("Hello 準備匿名內部類");  
  23.             }  
  24.         });  
  25.     }  
  26. }  

 其實在真正的專案開發中匿名內部類使用的非常之少,一般在Java的圖形介面和現在的Android中使用的比較多點。

 最後給一個內部類實現的簡單鏈表:

Java程式碼  收藏程式碼
  1. package com.iflytek.innerclass;  
  2. /** 
  3.  * @author xudongwang 2012-1-11 
  4.  *  
  5.  *         Email:[email protected] 
  6.  */  
  7. public class LinkDemo {  
  8.     public static void main(String args[]) {  
  9.         Link link = new Link();  
  10.         link.add("A");  
  11.         link.add("B");  
  12.         link.add("C");  
  13.         link.add("D");  
  14.         link.add("E");  
  15.         link.print();  
  16.     }  
  17. };  
  18. class Link {  
  19.     class Node {  
  20.         private String name;  
  21.         private Node next; // 單向連結串列,每個節點指向下一個節點  
  22.         public Node(String name) {  
  23.             this.name = name; // 通過構造方法為name屬性賦值  
  24.         }  
  25.         public void addNode(Node newNode) { // 增加節點  
  26.             if (this.next == null) {  
  27.                 this.next = newNode; // 儲存節點  
  28.             } else {  
  29.                 this.next.addNode(newNode); // 繼續向下查詢  
  30.             }  
  31.         }  
  32.         public void printNode() { // 輸出節點  
  33.             System.out.println(this.name);  
  34.             if (this.next != null) { // 此節點之後還存在其他的節點  
  35.                 this.next.printNode();  
  36.             }  
  37.         }  
  38.     };  
  39.     private Node root; // 連結串列的頭  
  40.     public void add(String name) { // 增加節點  
  41.         Node newNode = new Node(name); // 定義一個新的節點  
  42.         /* 
  43.          * 如果是第一個節點,則肯定是根節點, 如果是第二個節點,則肯定放在根節點next中 如果是第三個節點,則肯定放在第二個節點的next中 
  44.          */  
  45.         if (this.root == null) {  
  46.             this.root = newNode; // 將第一個節點設定成根節點  
  47.         } else {  
  48.             // 肯定要放在最後一個節點之後  
  49.             // 通過節點.next來不斷的判斷  
  50.             this.root.addNode(newNode);  
  51.         }  
  52.     }  
  53.     public void print() {  
  54.         if (this.root != null) { // 如果根節點為空了,則沒有任何內容  
  55.             this.root.printNode();  
  56.         }  
  57.     }  
  58. };