內部類(inner class)的簡單介紹


本文主要介紹內部類(inner class)的一些基本應用,將從內部類的分類角度,首先對每一個具體內部類進行介紹。主要包括普通的內部類【common inner class】、局部內部類[local inner class]、嵌套內部類【nested innner class】、匿名內部類【anonymous inner class】、然后比較一下局部內部類[local inner class]和匿名內部類【anonymous inner class ]的區別,進而知道在具體情況下該選擇內部類,即到底用local inner class還是anonymous inner class。最后介紹內部類的應用

一:首先對每一個具體內部類進行介紹

1.普通的內部類【common inner class】

定義:在一個類里面直接定義一個類:

一些詳細情況看代碼:

 1 package com.qls.comonInnerClass;
 2 
 3 public class A {
 4     /**
 5      * 從B C D E 這四個普通內部類中可以看出類前面的修飾符可以是
 6      * private  protected default(也就是什么修飾符沒有的D) public.  而在局部內部類中修飾類的只能是:
 7      * abstract 或final 或者什么修飾符都沒有。
 8      * 注意的問題如下:
 9      * 1.通常情況下:外部類會有一個返回內部類引用的一個方法如getB()這個方法。
10      * 2.如何在內部類中用this指代外部類引用?【答:外部類名.this 參考第19行代碼。】
11      * 以及如何創建內部類的一個實例?【答:x.new B() 其中x是外部類的一個實例,B為一個內部類。
12      * 若是直接寫new B()會報錯。參考第38、39兩行代碼。】
13      * 上述兩個注意點對其他的內部類也適用。
14      * @author 秦林森
15      *
16      */
17     private  class B {
18         public A outer(){
19             return A.this;//A.this是指代A的一個引用。
20         }
21     }
22     protected class C{
23         
24     }
25     class D{
26         
27     }
28     public class E{
29         
30     }
31     /**
32      * 返回內部類的引用:
33      */
34     B getB(){
35         return new B();
36     }
37     public static void main(String[] args) {
38         A a = new A();
39         B b = a.new B();
40     }
41 }

局部內部類【local innner class】

定義:把類定義在方法里面,或者是方法中的某一個區域中。

代碼如下:

 1 package com.qls.localInnerClass2;
 2 /**
 3  * 定義:the creation of an entire class within the scope of a method,or Nesting a class within 
 4  * a scope of a method.
 5  * This is called a local inner class.
 6  * 注意情況如下:
 7  * 1.局部內部類【local inner class】如果想要修飾的話,只有abstract 和final可以,
 8  * 其余的如(public protected)等都不可以。
 9  * 2.在局部內部類中只能訪問包含該內部類的范圍(enclosing scope)的final變量。若不是則會報錯。
10  * 
11  * @author 秦林森
12  *
13  */
14 public class A {
15     public void ouyangfeng(){
16         //把類D定義在方法ouyangfeng()的某個區域中。
17         if(3>2){
18             class D{
19                 
20             }
21         }
22         final class B{
23             
24         }
25     }
26     
27     public void  sixi(final String s){
28         int e=1;
29         final int c=8;
30         class C{
31             /**
32              * 在局部內部類或者匿名內部類中只能訪問包含該內部類的范圍(enclosing scope)的final變量。
33              * 若不是則會報錯。
34              * 如int f=e;編譯器報錯。
35              */
36             String str=s;
37             int d=c;
38 //            int f=e;//編譯器報錯。
39         }
40     }
41     public static void main(String[] args) {
42         // TODO Auto-generated method stub
43 
44     }
45 
46 }

匿名內部類:沒有名字的內部類。

下面的代碼介紹了以下的內容:

1.匿名內部類實現一個接口,

2.匿名內部類實現一個沒有默認構造方法的抽象類

3.匿名內部類和局部內部類一樣把參數定義成final,完成字段初始化

4.匿名內部類用普通代碼塊{}完成初始化,彌補了匿名內部類沒有構造方法的缺陷。

代碼如下:

package com.qls.anonymouseInnerClass;
/**
 * 匿名內部類(anonymous inner class)一般用在return 語句中。
 * 注意情況如下:
 * 匿名內部類由於沒有名字,自然而然也就沒有構造方法,其他三種內部類都有構造方法。
 * 沒有構造方法怎么給對象賦值進行初始化呢?【答:用普通的代碼塊{},在這個代碼塊里面實行初始化。】
 * @author 秦林森
 *
 */
interface B{
    void ouyangfeng();
}
abstract class C{
    private int i;
    public C(int i) {
        this.i=i;
    }
    public abstract int value();
    
}
public class A {
    public B getB(){
        //new B(){};就是匿名內部類:用默認的構造方法
        return new B() {
            
            @Override
            public void ouyangfeng() {
                // TODO Auto-generated method stub
                System.out.println("ouyangfeng is chief village of sixi ");
            }
        };
    }
    public C getC(final int i){
        //匿名內部類用一個帶參數的構造方法
        return new C(i) {
            //用普通代碼塊實現初始化:
            {
                //這里寫兩個輸出語句作為演示。
                System.out.println("泗溪");
                System.out.println("ouyangfeng");
                System.out.println(value());//輸出value的值
            }
            @Override
            public int value() {
                // TODO Auto-generated method stub
                return i;//從這里可以看出要想引用i,必須把i定義成final。這和局部內部類一樣。
            }
        };
        
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        new A().getC(4);//輸出泗溪、ouyangfeng、4
        
    }

}

 嵌套內部類:

 1 package com.qls.nestedClass;
 2 /**
 3  * 如果你不想讓內部類的對象和外部類的對象有如何聯系的話,你就可以把內部類定義成static
 4  * 嵌套內部類(Nested inner class)的定義:類中關鍵詞static修飾的內部類。
 5  * 注意情況如下:
 6  * 1.在嵌套內部類中不能訪問外部類的非靜態變量。
 7  * 2.創建內部類變量時,你不想通過創建外部類變量才能創建內部類變量時,你可以把這個內部類定義成static
 8  * 即嵌套內部類。
 9  * 3.在接口interface中定義的內部類默認都是public static 的,所以在接口中的內部類必是嵌套內部類。
10  * @author 秦林森
11  *
12  */
13 interface D{
14     void hello();
15     class Test implements D{
16 
17         @Override
18         public void hello() {
19             // TODO Auto-generated method stub
20             System.out.println("hello");
21         }
22         public static void main(String[] args) {
23             /**
24              * 由於Test類默認是public static 的,所以創建Test對象時,不需要通過外部類D,
25              * 所以直接new Test()即可創建Test類中的一個對象。
26              * 話又說回來了,如果在接口中的類不是public static 的那么這個內部類也就是普通的內部類
27              * 在創建Test的對象時,也就需要外部類的對象。關鍵D是接口,你怎么new 呢?
28              * 所以在的類只能是static 的。
29              */
30             new Test().hello();//輸出hello
31         }
32     }
33 }
34 public class A {
35     int a=9;
36     public static  class B{
37 //        int b=a;編譯報錯
38          void f(){
39             System.out.println("f()");
40         }
41     }
42     public static void main(String[] args) {
43         /**
44          * 從這里你看到了,可以對B直接new ,訪問B中的函數f().
45          * 但是如果B沒有static這個關鍵字,即B是普通內部類時,必須這樣才能訪問到f()
46          * new A().new B().f();
47          */
48         new B().f();
49     }
50 }

 二:比較一下局部內部類[local inner class]和匿名內部類【anonymous inner class ]的區別

1.匿名內部類沒有構造犯法,二局部內部類有構造方法。

2.如果在一個外部類有兩個或兩個以上的方法,返回的都是某個接口或者抽象類的引用,建議把寫一個局部內部類。若寫成匿名內部類時,代碼會顯得特別冗長。反之如果一個時,建議用匿名內部類。

代碼如下:

 1 package com.qls.anonymouseInnerClass;
 2 interface Six{
 3     void six();
 4 }
 5 public class Ouyangfeng {
 6     private class SixTest implements Six{
 7 
 8         @Override
 9         public void six() {
10             // TODO Auto-generated method stub
11             
12         }
13         
14     }
15     public Six f(){
16         return new SixTest();
17     }
18     public Six g(){
19         return new SixTest();
20     }
21 }

三:內部類的應用:

用內部類實現java的多重繼承。

 1 package com.qls.anonymouseInnerClass;
 2 class D{
 3     
 4 }
 5 abstract class E{
 6     
 7 }
 8 class F extends D{
 9     //這是實現多重繼承的核心代碼。這里是用一個匿名內部類實現
10     E makeE(){
11         return new E() {
12         };
13     }
14 }
15 public class MultipleInherit {
16     public static void takesD(D d){
17         
18     }
19     public static void takesE(E d){
20         
21     }
22     public static void main(String[] args) {
23         // TODO Auto-generated method stub
24         F d = new F();
25         takesD(d);
26         takesE(d.makeE());
27     }
28 
29 }

最后簡要介紹一下讓一個類繼承另一個類中的內部類?以及怎么讓一個類中的內部類繼承另一個類的內部類呢?

首先是:讓一個類繼承另一個類中的內部類

 代碼如下:

 1 package com.qls.anonymouseInnerClass;
 2 
 3 import com.qls.anonymouseInnerClass.WithInner.Inner;
 4 
 5 class WithInner{
 6     class Inner{
 7         private int a;
 8         public Inner(int a) {
 9             this.a=a;
10         }
11         public Inner() {
12             // TODO Auto-generated constructor stub
13         }
14     }
15 }
16 public class InheritInner extends Inner{
17     public InheritInner(WithInner withInner) {
18         // TODO Auto-generated constructor stub
19         /**
20          * 這句話必須要寫。否則編譯器會報錯。即:外部類的一個對象.super().
21          * 這里的super(),比奧斯Inner的一個默認構造方法。
22          * 如果Inner中比如有這樣一個構造方法:public Inner(int a) 
23          * 你現在也可以寫成:把withInner.super();改為withInner.super(1);編譯器是不會報錯的。
24          * 如果沒有默認構造方法public Inner() 則這題必須寫成:withInner.super(1);的形式。
25          */
26         
27         withInner.super();
28     }
29     public static void main(String[] args) {
30         // TODO Auto-generated method stub
31         WithInner withInner = new WithInner();
32         InheritInner inheritInner = new InheritInner(withInner);
33     }
34 
35 }

 讓一個類中的內部類繼承另一個類的內部類

代碼如下:

 1 package com.qls.anonymouseInnerClass;
 2 /**
 3  * 朱元璋家住鳳陽,劉伯溫家住青田
 4  * @author 秦林森
 5  *
 6  */
 7 class ZhuYuanZhang{
 8     class FengYang{
 9         private String location;
10 
11         public FengYang(String location) {
12             this.location = location;
13         }
14         
15     }
16 }
17 class LiuBoWei{
18     class QingTian extends ZhuYuanZhang.FengYang{
19         private String location;
20         public QingTian(ZhuYuanZhang zhuYuanZhang, String location) {
21             zhuYuanZhang.super(location);//這句話必須要寫。或者會報錯,
22             this.location=location;
23         }
24         public void accurate(){
25             System.out.println("一統江山劉伯溫 ,家在"+location);
26         }
27     }
28 }
29 public class Test {
30 
31     public static void main(String[] args) {
32         // TODO Auto-generated method stub
33         new LiuBoWei().new QingTian(new ZhuYuanZhang(), "青田").accurate();
34     }
35 
36 }/*Output:
37 一統江山劉伯溫 ,家在青田*///:~

 


免責聲明!

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



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