1. 程式人生 > 其它 >java中的四種內部類

java中的四種內部類

Java的四種內部類包括如下:

  • 成員內部類
  • 靜態內部類
  • 區域性內部類
  • 匿名內部類

成員內部類:定義在另一個類(外部類)的內部,而且與成員屬性和方法平級,故稱成員內部類。類比於外部類的非靜態方法,如果用

static修飾就變成了靜態內部類

靜態內部類:使用static修飾的成員內部類。類比於外部類的靜態方法。

區域性內部類:定義在程式碼塊內(使用花括號“{}”括起來的程式碼)、方法體內的內部類叫做區域性內部類。就如同方法裡面的一個區域性變數一

樣,在其所在的“區域性”之外不可見。

匿名內部類:區域性內部類的一種,本質是建立繼承了父類或者實現了父介面的子類的匿名物件。

成員內部類

定義在另一個類(外部類)的內部,而且與成員屬性和方法平級,故稱成員內部類。成員內部類相當於外部類的非靜態方法,如果用static修飾就變成了靜態內部類。

① 在外部類以外,成員內部類依賴於外部類的例項物件,只有先建立了外部類的例項物件後才能建立成員內部類的例項物件:

1 外部類.內部類 例項名稱 = new 外部類例項物件.new 內部類構造器(引數)

② 成員內部類中不能使用static關鍵字,即不能宣告靜態屬性、靜態方法、靜態程式碼塊等

③ 成員內部類在編譯之後會生成一個單獨的class檔案(外部類$內部類.class),裡面包含該成員內部類的定義,所以成員內部類中可以有和外部類同名的屬性和方法,但會發生隱藏現象。

④ 成員內部類訪問外部類成員。當成員內部類中有和外部類同名的屬性和方法時,會發生隱藏現象,及預設情況下訪問的是成員內部類中的屬性和方法。若想要訪問外部類的屬性和方法需要以下面的形式進行訪問(不論是否重名,都是這種方式)

1 外部類名.this.成員變數  // 訪問外部類的非靜態成員變數
2 外部類名.this.成員方法()  // 訪問外部類的非靜態成員方法
3 外部類名.靜態成員變數  // 訪問外部類的靜態成員變數
4 外部類名.靜態成員方法()  // 訪問外部類的靜態成員方法

⑤ 外部類訪問內部類的非靜態成員。外部類無法直接訪問成員內部類的方法和屬性,需要通過成員內部類的一個例項來訪問。在外部類中如果要訪問成員內部類的成員屬性或成員方法,必須先建立一個成員內部類的物件,然後通過指向這個物件的引用來訪問成員內部類的成員屬性或成員方法。

1 new 成員內部類的構造方法(引數).成員內部類的成員變數  // 訪問成員內部類的成員變數
2 new 成員內部類的構造方法(引數).成員內部類的成員方法()  // 訪問成員內部類的成員方法

⑥ 成員內部類可以擁有private訪問許可權、protected訪問許可權、包訪問許可權、public訪問許可權;而外部類只能有包訪問許可權和public訪問許可權。因為成員內部類就如同外部類的一個成員,所以可以像類的成員一樣擁有多種訪問許可權修飾。

⑦ 與外部類平級的類繼承成員內部類是,其構造方法中需要出入外部類的例項物件,且在構造方法的第一句呼叫“外部類例項物件.super(內部類引數)”

⑧ 成員內部類可以是抽象類,即用abstract修飾。

 1 package com.lqx;
 2 
 3 class Outer {  // 外部類
 4     private int a = 3;
 5     private Inner inner;
 6     public Outer(){
 7         inner = new Inner();
 8     }
 9 
10     public int getInnerA(){
11         return inner.a;  // 外部類訪問內部類的成員需要通過成員內部類
12     }
13 
14     public class Inner {  // 成員內部類,相當於外部類的非靜態方法
15         public int a = 2;  // // 內部類的成員隱藏了外部類同名的成員
16         public void doSomething(){
17             System.out.println(Outer.this.a);  // 成員內部類訪問外部類的成員
18             System.out.println(a);  
19         }
20     }
21 }
22 
23 public class Test{
24     public static void main(String [] args){
25         Outer outer = new Outer();
26         System.out.println(outer.getInnerA());
27         // Outer.Inner inner = outer.new Inner();
28         Outer.Inner inner = new Outer().new Inner();  // 成員內部類的例項化依賴於外部類的例項物件
29         inner.doSomething();
30     }
31 }
32 
33 class Extender extends Outer.Inner{
34     public Extender(Outer outer){  // 構造需要外部類的例項物件
35         outer.super();  // 外部類例項物件.super(成員內部類引數)
36     }
37 }

靜態內部類

使用static修飾的成員內部類。有點類似於外部類的靜態方法。

① 在外部類外部,靜態內部類不依賴於外部類的例項物件,靜態內部類例項化時不需要先例項化外部類,在沒有外部類物件的情況下就可以建立靜態內部類的例項物件。

1 外部類.內部類 例項名稱 = new 外部類名.內部類構造器(引數)

② 靜態內部類中可以有靜態成員變數和靜態成員方法。

③ 成員內部類在編譯之後會生成一個單獨的class檔案(外部類$內部類.class),裡面包含該成員內部類的定義。所以成員內部類中可以有和外部類同名的屬性和方法。

④ 靜態內部類只能訪問外部類的靜態成員屬性和靜態成員方法。與靜態方法類似,靜態內部類不能使用外部類的非靜態成員變數和非靜態成員方法。

1 外部類名.靜態成員屬性
2 外部類名.靜態成員方法()

⑤ 外部類訪問靜態內部類的成員。外部類無法直接訪問成員內部類的方法和屬性,需要通過成員內部類的一個例項來訪問。在外部類中如果要訪問成員內部類的成員屬性或成員方法,必須先建立一個成員內部類的物件,然後通過指向這個物件的引用來訪問成員內部類的成員屬性或成員方法。

1 new 靜態內部類的構造方法(引數).成員內部類的成員變數  // 訪問靜態內部類的非靜態成員變數
2 new 靜態內部類的構造方法(引數).成員內部類的成員方法()  // 訪問靜態內部類的非靜態成員方法
3 靜態內部類名.靜態成員變數  // 訪問靜態內部類的靜態成員變數
4 靜態內部類名.靜態成員方法()  // 訪問靜態內部類的靜態成員方法

⑥ 靜態內部類的訪問許可權。靜態內部類可以擁有private訪問許可權、protected訪問許可權、包訪問許可權、public訪問許可權;而外部類只能有包訪問許可權和public訪問許可權。因為成員內部類就如同外部類的一個成員,所以可以像類的成員一樣擁有多種訪問許可權修飾。

⑦ 靜態內部類可以是抽象類,即用abstract修飾。

區域性內部類

定義在程式碼塊內(使用花括號“{}”括起來的程式碼)、方法體內的內部類叫做區域性內部類。就如同方法裡面的一個區域性變數一樣,在其所在的“區域性”之外不可見。

① 區域性內部類只能在“區域性”宣告建立例項物件。

1 區域性內部類名 物件名 = new 區域性內部類的構造方法(引數)

② 不能用訪問許可權修飾符(public、protected、private)修飾區域性內部類,因為區域性內部類不是類類成員,其身份和區域性變數類似。但可以用訪問修飾符修飾區域性內部類中的成員。

③ 不能用static修飾,不能有static屬性和static方法。區域性變數也不能用static修飾。

④ 區域性內部類可以訪問外部類的所有成員,也可以訪問其所在“區域性”的區域性常量(final)。

1 外部類名.this.外部類的非靜態成員屬性  // 訪問外部類的非靜態成員屬性
2 外部類名.this.外部類的非靜態成員方法()  // 訪問外部類的非靜態成員方法
3 外部類名.外部類的靜態成員屬性  // 訪問外部類的靜態成員屬性
4 外部類名.外部類的靜態成員方法()  // 訪問外部類的靜態成員方法
5 區域性常量名  // 直接訪問區域性常量,當局部內部類的成員變數和區域性內部類所在方法的區域性常量重名時,後者會被隱藏。

⑤ 外部類無法訪問區域性內部類的成員,因為在區域性內部類所在的“區域性”之外是不可見的。就跟區域性變數在其作用域之外是不可見的一個道理

⑥ 區域性內部類可以是抽象類,用abstract修飾。

⑦ 編譯之後生成的class檔案的名稱為:外部類名$[123...]內部類名.class

匿名內部類

① 匿名內部類本質是建立繼承了父類或者實現了父介面的子類的匿名物件。

② 匿名內部類是區域性內部類的一種,要符合區域性內部類的要求。

③ 匿名內部類必須繼承一個類(抽象類、非抽象類都可以)或者實現一個介面。如果父類(或者父介面)是抽象類,必須實現所有的抽象方法。直接使用new建立一個例項物件之後,類定義會立即消失(若想要多次使用就要用到反射的知識了)

1 new 父類構造器 (引數列表) {
2     // 如果父類是抽象的,實現所有的抽象方法   
3 }
4 或者
5 new 介面名() {
6     // 實現所有的抽象方法
7 }

③ 匿名內部類不能是抽象類,因為匿名內部類在定義之後,會立即建立一個例項物件。

④ 匿名內部類中不能定義構造方法。利用構造程式碼塊來初始化匿名內部類的成員

⑤ 匿名內部類編輯之後生成的class檔名為:外部類名$[123...].class (按照生成的先後順序)

 1 package com.niMingNeiBuLei;
 2 
 3 abstract class InnerClass{  // 匿名內部類的前提必須有一個類或者介面
 4     public abstract String getName();
 5     public abstract int getAge();
 6 }
 7 public class OutClass {
 8     public InnerClass getInnerClass(final int age,final String name){  // 匿名內部類訪問外部常量
 9         return new InnerClass() {
10             int age_ ;
11             String name_;
12             
13             {  // 構造程式碼塊完成初始化工作
14                 if(0 < age && age < 200){
15                     age_ = age;
16                     name_ = name;
17                 }
18             }
19             
20             @Override
21             public String getName() {  // 匿名內部類實現抽象方法
22                 return name_;
23             }
24             @Override
25             public int getAge() {  // 匿名內部類實現抽象方法
26                 return age_;
27             }
28         };
29     }
30 
31     public static void main(String[] args) {
32         OutClass out = new OutClass();
33 
34         InnerClass inner_1 = out.getInnerClass(18, "Chenssy");
35         System.out.println(inner_1.getName() + " " + inner_1.getAge());
36 
37         InnerClass inner_2 = out.getInnerClass(23, "Tom");
38         System.out.println(inner_2.getName() + "、 " + inner_2.getAge());
39     }
40 }