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
!!!