深刻理解java嵌套類和內部類、匿名類

1、什麼是嵌套類及內部類前端

  能夠在一個類的內部定義另外一個類,這種類稱爲嵌套類(nested classes),它有兩種類型:靜態嵌套類和非靜態嵌套類。靜態嵌套類使用不多,最重要的是非靜態嵌套類,也便是被稱做爲內部類(inner)。嵌套類從JDK1.1開始引入。其中inner類又可分爲三種:
  其1、在一個類(外部類)中直接定義的內部類;
  其2、在一個方法(外部類的方法)中定義的內部類;
  其3、匿名內部類。
java

  下面,我將說明這幾種嵌套類的使用及注意事項。ide

2、靜態嵌套類this

  以下所示代碼爲定義一個靜態嵌套類,
spa

  1. public class StaticTest {   .net

  2.         private static String name = "javaJohn";           orm

  3.   private String id = "X001";  對象

  4.   static class Person{  接口

  5.     private String address = "swjtu,chenDu,China";  事件

  6.     public String mail = "josserchai@yahoo.com";//內部類公有成員  

  7.     public void display(){  

  8.       //System.out.println(id);//不能直接訪問外部類的非靜態成員  

  9.       System.out.println(name);//只能直接訪問外部類的靜態成員  

  10.       System.out.println("Inner "+address);//訪問本內部類成員。  

  11.     }  

  12.   }  

  13.   

  14.   public void printInfo(){  

  15.     Person person = new Person();  

  16.     person.display();  

  17.     //System.out.println(mail);//不可訪問  

  18.     //System.out.println(address);//不可訪問  

  19.     System.out.println(person.address);//能夠訪問內部類的私有成員  

  20.     System.out.println(person.mail);//能夠訪問內部類的公有成員  

  21.   

  22.   }  

  23.   public static void main(String[] args) {  

  24.   StaticTest staticTest = new StaticTest();  

  25.   staticTest.printInfo();  

  26. }  

  27. }  



  在靜態嵌套類內部,不能訪問外部類的非靜態成員,這是由Java語法中"靜態方法不能直接訪問非靜態成員"所限定。若想訪問外部類的變量,必須經過其它方法解決,因爲這個緣由,靜態嵌套類使用不多。注意,外部類訪問內部類的的成員有些特別,不能直接訪問,但能夠經過內部類來訪問,這是由於靜態嵌套內的全部成員和方法默認爲靜態的了。同時注意,內部靜態類Person只在類StaticTest 範圍內可見,若在其它類中引用或初始化,均是錯誤的。

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

  以下所示代碼爲在外部類中定義兩個內部類及它們的調用關係:
  

  1. public class Outer {   

  2.            int outer_x = 100;  

  3.     class Inner{  

  4.       public int y = 10;  

  5.       private int z = 9;  

  6.       int m = 5;  

  7.       public void display(){  

  8.         System.out.println("display outer_x:"+ outer_x);  

  9.       }  

  10.       private void display2(){  

  11.         System.out.println("display outer_x:"+ outer_x);  

  12.       }  

  13.     }  

  14.     void test(){  

  15.       Inner inner = new Inner();  

  16.       inner.display();  

  17.       inner.display2();  

  18.       //System.out.println("Inner y:" + y);//不能訪問內部內變量  

  19.       System.out.println("Inner y:" + inner.y);//能夠訪問  

  20.       System.out.println("Inner z:" + inner.z);//能夠訪問  

  21.       System.out.println("Inner m:" + inner.m);//能夠訪問  

  22.       InnerTwo innerTwo = new InnerTwo();  

  23.       innerTwo.show();  

  24.     }  

  25.     class InnerTwo{  

  26.       Inner innerx = new Inner();  

  27.       public void show(){  

  28.         //System.out.println(y);//不可訪問Innter的y成員  

  29.         //System.out.println(Inner.y);//不可直接訪問Inner的任何成員和方法  

  30.         innerx.display();//能夠訪問  

  31.         innerx.display2();//能夠訪問  

  32.         System.out.println(innerx.y);//能夠訪問  

  33.         System.out.println(innerx.z);//能夠訪問  

  34.         System.out.println(innerx.m);//能夠訪問  

  35.       }  

  36.     }  

  37.     public static void main(String args[]){  

  38.       Outer outer = new Outer();  

  39.       outer.test();  

  40.     }  

  41.   }  



  以上代碼須要說明有,對於內部類,一般在定義類的class關鍵字前不加public 或 private等限制符,若加了沒有任何影響,同時好像這些限定符對內部類的變量和方法也沒有影響(?)。另外,就是要注意,內部類Inner及InnterTwo只在類Outer的做用域內是可知的,若是類Outer外的任何代碼嘗試初始化類Inner或使用它,編譯就不會經過。同時,內部類的變量成員只在內部內內部可見,若外部類或同層次的內部類須要訪問,需採用示例程序中的方法,不可直接訪問內部類的變量。



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


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

前端時間在寫.net項目中,一直錯將.cs裏的兩個class看成內部類,原來是一個文件裏的兩個類而已,這讓我想起了Java中的內部類,比較內部類,那麼還有兩個類,那就是匿名類和匿名內部類。今天我想就Java中的這三種類進行個比較。

咱們知道在Java語言規範中能夠作不少事,例如一個類或一個接口中能夠聲明一個類或接口,在一個方法中能夠聲明一個類,類與接口聲明能夠嵌套任意深度等。

 

匿名類:

      一、new <類或接口><類的主體>,匿名類的聲明是在編譯時進行的,實例化是在運行時進行的,因此在for循環中一個new語句會建立相同匿名類的幾個實例,而不是建立幾個不一樣匿名類的一個實例。

      二、若是要執行的對象須要一個對象,但卻不值得建立全新的對象(多是由於該對象只在一個方法內部使用),在這個時候使用匿名類就會很是合適,因此說,匿名類通常會在swing程序中快速建立事件處理程序。

Java代碼  收藏代碼

  1. firstButton.addActionListener(new ActionListener() {  

  2.         @Override  

  3.         public void actionPerformed(ActionEvent e) {  

  4.             getTxtValue().setText("第一個按鈕觸發的事件!");  

  5.         }  

  6.     });   

       三、從技術上說,匿名類能夠被看做非靜態的內部類,因此他們具備方法內部聲明的非靜態內部類相同的權限和限制。

 

 

內部類:

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

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo {  

  9.     public static void main(String[] args) {  

  10.         new Outer().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer {  

  15.   

  16.     private String name = "Hello 內部類";  

  17.   

  18.     class Inner {  

  19.         public void print() {  

  20.             System.out.println("name = " + name);  

  21.   

  22.         }  

  23.     };  

  24.   

  25.     public void fun() {  

  26.         new Inner().print();  

  27.     }  

  28. }  

 

 內部類生成的.class文件名爲:Outer$Inner.class,從上面的結構發現內部類的的缺點是「結構很是的混亂」。

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo02 {  

  9.     public static void main(String[] args) {  

  10.         new Outer02().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer02 {  

  15.   

  16.     private String name = "Hello 內部類";  

  17.   

  18.     public void fun() {  

  19.         new Inner02(this).print();  

  20.     }  

  21.   

  22.     public String getName() {  

  23.   

  24.         return this.name;  

  25.     }  

  26. };  

  27.   

  28. class Inner02 {  

  29.     private Outer02 out;  

  30.   

  31.     public Inner02(Outer02 out) {  

  32.         this.out = out;  

  33.     }  

  34.   

  35.     public void print() {  

  36.         System.out.println("name = " + this.out.getName());  

  37.   

  38.     }  

  39. };  

 從上能夠看出內部類的優勢是「能夠方便的訪問外部類中的私有成員」;

若是要在外部直接使用內部類的實例化對象:

      外部類.內部類 內部類對象 = 外部類實例.new 內部類實例();

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang  2012-1-11 

  5.  * 

  6.  *  Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo03 {  

  9.     public static void main(String[] args) {  

  10.         Outer03 out = new Outer03();//外部類實例  

  11.         Outer03.Inner inner = out.new Inner();//實例化內部類對象  

  12.         inner.print();  

  13.     }  

  14. }  

  15. class Outer03{  

  16.     private String name = "Hello 內部類";  

  17.     class Inner {  

  18.         public void print() {  

  19.             System.out.println("name = " + name);  

  20.         }  

  21.     }  

  22. }  

 

 一個內部類若是使用static關鍵字聲明的話,則此內部類就將成爲外部類,能夠直接經過外部類.內部類的形式訪問

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo04 {  

  9.     public static void main(String[] args) {  

  10.         Outer04.Inner inner = new Outer04.Inner();// 實例化內部類對象  

  11.         inner.print();  

  12.     }  

  13. }  

  14.   

  15. class Outer04 {  

  16.     private static String name = "Hello 內部類";  

  17.   

  18.     static class Inner {  

  19.         public void print() {  

  20.             System.out.println("name = " + name);  

  21.         }  

  22.     }  

  23. }  

 

 內部類能夠在任意的地方使用,例如方法中聲明

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo05 {  

  9.     public static void main(String[] args) {  

  10.         new Outer05().fun();  

  11.     }  

  12. }  

  13.   

  14. class Outer05 {  

  15.     private static String name = "Hello 內部類";  

  16.   

  17.     public void fun() {  

  18.         class Inner {  

  19.             public void print() {  

  20.                 System.out.println("name = " + name);  

  21.             }  

  22.         }  

  23.         new Inner().print();  

  24.     }  

  25. }  

 

 在方法中定義的內部類,能夠直接訪問外部類中的各個成員,可是若是要訪問方法中的參數,則須要在參數上加上final關鍵字聲明;

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class InnerClassDemo06 {  

  9.     public static void main(String[] args) {  

  10.         new Outer06().fun(20);  

  11.     }  

  12. }  

  13.   

  14. class Outer06 {  

  15.     private static String name = "Hello 內部類";  

  16.   

  17.     public void fun(final int temp) {  

  18.         class Inner {  

  19.             public void print() {  

  20.                 System.out.println("temp = " + temp);  

  21.                 System.out.println("name = " + name);  

  22.             }  

  23.         }  

  24.         new Inner().print();  

  25.     }  

  26. }  

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

按所在位置能夠分爲兩大類:

      一、在類的方法中

                     特色:

                              a、能夠訪問宿主類的全部元素 ;

                              b、保存宿主類對象的引用,建立對象時必須有宿主類對象;

                              c、 不能有靜態數據;

繼續劃分:

                             A、本地內部類;

                             B、匿名內部類

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

      二、在類或接口做用域中;

                     繼續劃分:

                            A、普通內部類

                            B、靜態內部類

 

 

匿名內部類:

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

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class NoNameClass01 {  

  9.     public static void main(String[] args) {  

  10.         new X().fun2();  

  11.     }  

  12. }  

  13.   

  14. interface A {  

  15.     public void fun();  

  16. }  

  17.   

  18. class B implements A {  

  19.     public void fun() {  

  20.   

  21.         System.out.println("Hello 準備匿名內部類");  

  22.     }  

  23. }  

  24.   

  25. class X {  

  26.     public void fun1(A a) {  

  27.         a.fun();  

  28.     }  

  29.   

  30.     public void fun2() {  

  31.         this.fun1(new B());  

  32.     }  

  33. }  

 經過上面的Demo,若是如今假設B類只使用一次,那麼還有必要將其定義成一個單獨的類麼?

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

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class NoNameClass02 {  

  9.   

  10.     public static void main(String[] args) {  

  11.         new XX().fun2();  

  12.     }  

  13. }  

  14.   

  15. interface AA {  

  16.     public void fun();  

  17. }  

  18.   

  19. class XX {  

  20.     public void fun1(AA a) {  

  21.         a.fun();  

  22.     }  

  23.     public void fun2() {  

  24.         this.fun1(new AA() {  

  25.             public void fun() {  

  26.                 System.out.println("Hello 準備匿名內部類");  

  27.             }  

  28.         });  

  29.     }  

  30. }  

 其實在真正的項目開發中匿名內部類使用的很是之少,通常在Java的圖形界面和如今的Android中使用的比較多點。

 

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

Java代碼  收藏代碼

  1. package com.iflytek.innerclass;  

  2.   

  3. /** 

  4.  * @author xudongwang 2012-1-11 

  5.  *  

  6.  *         Email:xdwangiflytek@gmail.com 

  7.  */  

  8. public class LinkDemo {  

  9.     public static void main(String args[]) {  

  10.         Link link = new Link();  

  11.         link.add("A");  

  12.         link.add("B");  

  13.         link.add("C");  

  14.         link.add("D");  

  15.         link.add("E");  

  16.         link.print();  

  17.     }  

  18. };  

  19.   

  20. class Link {  

  21.     class Node {  

  22.         private String name;  

  23.         private Node next; // 單向鏈表,每一個節點指向下一個節點  

  24.   

  25.         public Node(String name) {  

  26.             this.name = name; // 經過構造方法爲name屬性賦值  

  27.         }  

  28.   

  29.         public void addNode(Node newNode) { // 增長節點  

  30.             if (this.next == null) {  

  31.                 this.next = newNode; // 保存節點  

  32.             } else {  

  33.                 this.next.addNode(newNode); // 繼續向下查找  

  34.             }  

  35.         }  

  36.   

  37.         public void printNode() { // 輸出節點  

  38.             System.out.println(this.name);  

  39.             if (this.next != null) { // 此節點以後還存在其餘的節點  

  40.                 this.next.printNode();  

  41.             }  

  42.         }  

  43.     };  

  44.   

  45.     private Node root; // 鏈表的頭  

  46.   

  47.     public void add(String name) { // 增長節點  

  48.         Node newNode = new Node(name); // 定義一個新的節點  

  49.         /* 

  50.          * 若是是第一個節點,則確定是根節點, 若是是第二個節點,則確定放在根節點next中 若是是第三個節點,則確定放在第二個節點的next中 

  51.          */  

  52.         if (this.root == null) {  

  53.             this.root = newNode; // 將第一個節點設置成根節點  

  54.         } else {  

  55.             // 確定要放在最後一個節點以後  

  56.             // 經過節點.next來不斷的判斷  

  57.             this.root.addNode(newNode);  

  58.         }  

  59.     }  

  60.   

  61.     public void print() {  

  62.         if (this.root != null) { // 若是根節點爲空了,則沒有任何內容  

  63.             this.root.printNode();  

  64.         }  

  65.     }  

  66. };  

相關文章
相關標籤/搜索