Java 內部類

1. 簡介html

在 Java 中能夠將一個類定義在另外一個類裏面或者一個方法裏面,這樣的類稱爲內部類。普遍意義上的內部類通常來講包括這四種:java

成員內部類、局部內部類、匿名內部類和靜態內部類。ide

 

2. 優勢this

在程序設計中有時會存在一些使用接口很難解決的問題,此時能夠利用內部類提供的、能夠繼承多個具體的或者抽象的類的能力來解決。spa

能夠這樣說,接口只是解決了部分問題,而內部類使得多重繼承的解決方案變得更加完整。.net

使用內部類可使程序擁有如下特性:設計

1)內部類能夠用多個實例,每一個實例都有本身的狀態信息,而且與其餘外圍對象的信息相互獨立;code

2)在單個外部類中,可讓多個內部類以不一樣的方式實現同一個接口,或者繼承同一個類;htm

3)建立內部類對象的時刻並不依賴於外部類對象的建立;對象

4)內部類並無使人迷惑的「is-a」關係,它就是一個獨立的實體;

5)內部類提供了更好的封裝,除了該外部類,其餘類都不能訪問;

 

3. 示例

3.1 成員內部類

3.1.1 成員內部類的修飾符和實例化

成員內部類能夠看做是外部類的一個成員,它有如下注意點:

1)成員內部類不能使用static關鍵字;

2)成員內部類的實例化:成員內部類依賴於外部類,所以必須在外部類實例化後內部類才能實例化。

注:上述條件說明在外部類的非靜態方法中能夠實例化內部類(要訪問外部類的實例方法,先要有外部類對象,知足上述條件);

或者在外部類的靜態方法中先實例化外部類,再實例化內部類。

 1 public class OuterClass1 {
 2 
 3     class InnerClass{
 4         //private static int innerVar = 1;         // 成員內部類不能使用靜態成員變量
 5         //private static void innerMethod(){ }     // 成員內部類不能使用靜態方法
 6     }
 7 
 8     public void outMethod(){
 9         InnerClass in = new InnerClass();      // 在外部類的非靜態方法中直接實例化內部類
10     }
11 
12     public static void main(String[] args){
13         //InnerClass in = new InnerClass();       // 在外部類的靜態方法中不能直接實例化內部類
14 
15         // 先建立外部類對象後才能建立內部類對象
16         OuterClass1 out = new OuterClass1();
17         OuterClass1.InnerClass in = out.new InnerClass();
18         // 外部類的非靜態方法之因此能夠建立內部類對象,是因爲要訪問外部類的非靜態方法,必須經過外部類的對象訪問,
19         // 此時已經建立了外部類對象,知足了先外部對象,再內部對象的條件
20         out.outMethod();
21     }
22 }

3.1.2 成員內部類訪問外部類

 成員內部類在訪問外部類時,它有如下注意事項:

1)成員內部類訪問外部類的非同名成員變量和方法:直接調用便可;

2)成員內部類訪問外部類的同名成員變量和方法:外部類.this.成員變量 / 外部類.this.成員方法;

注:不管外部類的成員變量和方法是否使用private修飾皆可訪問。

 1 public class OuterClass2 {
 2     private String outVar1 = "outVar1";
 3     private static String outVar2 = "outVar2";
 4     private String outVar3 = "outVar3";
 5 
 6     private void outerMethod(){
 7         System.out.println("outerMethod with same name of OuterClass");
 8     }
 9 
10     private void outerMethod1(){
11         System.out.println("outerMethod of OuterClass");
12     }
13 
14     private static void outerMethod2(){
15         System.out.println("static outerMethod of OuterClass");
16     }
17 
18     class InnerClass{
19         private String outVar3 = "innerVar3";
20 
21         private void outerMethod(){
22             System.out.println("outerMethod with same name of InnerClass");
23             System.out.println(outVar1);                      // 訪問外部類成員變量
24             System.out.println(outVar2);                      // 訪問外部類靜態成員變量
25             System.out.println(OuterClass2.this.outVar3);     // 訪問外部類同名成員變量
26         }
27 
28         public void innerMethod(){
29             outerMethod();                       // 訪問自身的同名方法
30             OuterClass2.this.outerMethod();      // 訪問外部類的同名方法
31             outerMethod1();                      // 訪問外部類的實例方法
32             outerMethod2();                      // 訪問外部類的靜態方法
33         }
34     }
35 
36     public static void main(String[] args){
37         OuterClass2 out = new OuterClass2();
38         OuterClass2.InnerClass in = out.new InnerClass();
39         in.innerMethod();
40     }
41 }

運行結果以下:

1 outerMethod with same name of InnerClass
2 outVar1
3 outVar2
4 outVar3
5 outerMethod with same name of OuterClass
6 outerMethod of OuterClass
7 static outerMethod of OuterClass

3.1.3 外部類訪問成員內部類

外部類在訪問成員內部類時,它有如下注意事項:

1)外部類訪問成員內部類時必須經過內部類的對象訪問;

 1 public class OuterClass3 {
 2 
 3     class InnerClass{
 4         private String innerVar1 = "innerVar1";
 5 
 6         private void outerMethod1(){
 7             System.out.println("outerMethod with same name of InnerClass");
 8         }
 9     }
10 
11     private void outerMethod1(){
12         System.out.println("outerMethod with same name of OuterClass");
13         InnerClass in = new InnerClass();      // 經過內部類對象訪問內部類的成員變量和方法
14         System.out.println(in.innerVar1);
15         in.outerMethod1();
16     }
17 
18     private static void outerMethod2(){
19         System.out.println("static method with same name of OuterClass");
20        // InnerClass in = new InnerClass();      // error
21         OuterClass3 out = new OuterClass3();     // 經過內部類對象訪問內部類的成員變量和方法
22         OuterClass3.InnerClass in = out.new InnerClass();
23         in.outerMethod1();
24     }
25 
26     public static void main(String[] args){
27         OuterClass3 out = new OuterClass3();
28         out.outerMethod1();
29         outerMethod2();
30     }
31 }

運行結果以下:

1 outerMethod with same name of OuterClass
2 innerVar1
3 outerMethod with same name of InnerClass
4 static method with same name of OuterClass
5 outerMethod with same name of InnerClass

 

3.2 靜態內部類

3.2.1 靜態內部類的說明和使用

靜態內部類指使用static關鍵字修飾的內部類。非靜態內部類在編譯完成以後會隱含地保存着一個引用,該引用是指向建立它的外部類,

靜態內部類卻沒有該引用,這是由於靜態內部類是類級別的屬性,不須要對象的引用(this)來調用。

它的特色以下:

0)加載外部類時不會直接加載靜態內部類,當且僅當靜態內部類的靜態成員(靜態域、構造器、靜態方法等)被調用時纔會加載;

1)靜態內部類的對象建立不依賴於外部類;

2)靜態內部類不能使用外部類的任何非靜態成員變量和方法,只能訪問靜態成員變量和方法;

3)外部類能夠經過類名.xx直接訪問靜態內部類的靜態方法;

 1 public class OuterClass4 {
 2     private String outVar1 = "outVar1";
 3     private static String outVar2 = "outVar2";
 4     private static String outVar3 = "outVar3";
 5 
 6     public void outMethod1(){
 7         InnerClass in = new InnerClass();
 8         System.out.println(in.outVar3);
 9     }
10 
11     private static void outMethod2(){
12     }
13 
14     private static void outMethod3(){
15         System.out.println(InnerClass.outVar4);          // 能夠直接訪問靜態內部類的靜態變量和方法
16         InnerClass in = new InnerClass();
17         in.innerMethod();
18         System.out.println(in.outVar3);                  // 能夠經過內部類對象訪問實例變量和方法
19     }
20 
21     static class InnerClass {
22         private String outVar3 = "innerVar3";
23         private static String outVar4 = "innerVar4";
24 
25         public InnerClass(){
26 //            System.out.println(outVar1);              // 不能訪問外部類的非靜態變量
27             System.out.println(outVar2);                // 能夠訪問外部類的靜態變量
28             System.out.println(OuterClass4.outVar3);   //  能夠訪問外部類的同名靜態變量
29 
30             //outMethod1();            // 不能訪問外部類的非靜態方法
31             outMethod2();              // 能夠訪問外部類的靜態方法
32         }
33 
34         public void innerMethod(){
35         }
36     }
37 
38     public static void main(String[] args){
39         InnerClass in = new InnerClass();       // 能夠直接建立內部類對象
40         System.out.println(in.outVar3);
41 
42         OuterClass4 out = new OuterClass4();
43         out.outMethod1();
44         outMethod3();
45     }
46 }

 運行結果以下:

 1 outVar2
 2 outVar3
 3 innerVar3
 4 outVar2
 5 outVar3
 6 innerVar3
 7 innerVar4
 8 outVar2
 9 outVar3
10 innerVar3

 

3.3 局部內部類

3.3.1局部內部類的說明和使用

局部內部類是定義在一個方法或者做用域中的類,它的使用僅限於其方法或者做用域內,出了方法和做用域就會失效,相似於局部變量。其特色以下:

1)局部內部類是定義在一個方法或者做用域中的類,它的訪問權限僅限於其方法或者做用域內;

2)局部內部類相似方法和做用域中的局部變量,不能使用權限訪問修飾符和static關鍵字修飾;

 1 class Animal{ }
 2 
 3 public class OuterClass5 {
 4 
 5     // 在方法中使用局部內部類
 6     private Animal getDog(){
 7         class Dog extends Animal{
 8         }
 9         return new Dog();
10     }
11 
12     // 在做用域中使用局部內部類
13     private Animal getCat(boolean flag){
14         if(flag){
15             class Cat extends Animal{
16             }
17             return new Cat();
18         }
19         return null;
20     }
21 
22     public static void main(String[] args){
23         OuterClass5 out = new OuterClass5();
24         Animal a1 = out.getDog();
25         Animal a2 = out.getCat(true);
26         System.out.println(a1);
27         System.out.println(a2);
28     }
29 }

運行結果以下:

1 InnerClass.OuterClass5$1Dog@6d6f6e28
2 InnerClass.OuterClass5$1Cat@135fbaa4

 

3.4 匿名內部類

3.4.1 匿名內部類的說明

匿名內部類便是沒有名稱的內部類它的使用前提和特色以下:

1)使用匿名內部類須要繼承父類或者實現一個接口;

2)匿名內部類不能使用訪問修飾符修飾;

3)匿名內部類不能是抽象類,由於在使用它時會直接建立該類的對象;

4)匿名內部類不能定義構造器由於該類沒有類名;

3.4.2 未在抽象類和接口上使用匿名內部類

對於一個抽象類和接口,一般須要使用一個類繼承或實現它們,而後再實現其內部的方法,最後使用它。例如:

 1 abstract class Parent{
 2     abstract int getNumber(int n);
 3 }
 4 
 5 class Child extends Parent{
 6     @Override
 7     int getNumber(int n) {
 8         return n;
 9     }
10 }
11 
12 public class Demo {
13     public static void main(String[] args){
14         Parent p = new Child();
15         System.out.println(p.getNumber(2));
16     }
17 }

3.4.3 抽象類上使用匿名內部類

對於上述抽象類Parent,咱們顯示地定義了一個Child類繼承它而且重寫了其方法,有什麼方法能夠不寫這個Child類呢?

這裏引入匿名內部類便可,例如如下示例:

 1 abstract class Parent {
 2     abstract int getNumber(int n);
 3 }
 4 
 5 public class Demo1 {
 6     public static void main(String[] args){
 7         Parent p = new Parent() {           // 注意,這裏使用了匿名內部類 
 8             @Override
 9             public int getNumber(int n) {
10                 return n;
11             }
12         };
13         System.out.println(p.getNumber(2));
14     }
15 }

3.4.4 在接口上使用匿名內部類

 1 interface Parent {
 2     int getNumber(int n);
 3 }
 4 
 5 public class Demo2 {
 6     public static void main(String[] args){
 7         // 直接使用
 8         Parent p1 = new Parent() {     // 沒有出現類名
 9             @Override
10             public int getNumber(int n) {
11                 return n;
12             }
13         };
14         System.out.println(p1.getNumber(2));
15 
16         // 使用Lambda表達式
17         Parent1 p2 = n -> n;
18         System.out.println(p2.getNumber(2));
19     }
20 }

 

4. 參考文獻

https://www.runoob.com/w3cnote/java-inner-class-intro.html

https://www.cnblogs.com/nerxious/archive/2013/01/25/2876489.html

http://www.javashuo.com/article/p-zhxupjja-y.html

http://www.javashuo.com/article/p-qxqvuwlq-eb.html

!!!

相關文章
相關標籤/搜索