還記得在剛學習內部類時,常常對外部類以及各類內部類傻傻分不清楚,等到後來知道是怎麼一回過後,又隨着時間的流逝,再要說出個大概倒是什麼都回顧不起來了,所以本文就對內部類作個回顧。java
關於內部類的定義就是能夠將一個類的定義放在另外一個類的定義內部
,內部類是一種很是有用的特性,它容許咱們把一些邏輯相關的類組織在一塊兒,而且能夠控制位於內部的類的可視性。對於上面提到的各類內部類,咱們能夠大概分爲下面張圖片的分類:多線程
從上圖中能夠看到,內部類分紅靜態內部類和非靜態內部類,而非靜態內部類又能夠分爲局部內部類和匿名內部類,同時咱們把包裹內部類的類稱之爲外部類,就以下:app
class OuterClass {
...
// 靜態內部類
static class StaticInnerClass {
...
}
// 非靜態內部類
class InnerClass {
...
}
}
複製代碼
外部類可使用 public 或者默認包權限來修飾,而內部類則可使用 private、protected、public 以及包權限進行修飾。使用內部類和咱們平時使用普通類並沒什麼不一樣,此外當生成內部類對象的時候,內部類持有當前外部類的引用,經過這個引用它能夠訪問外部類全部的成員變量,包括私有變量
,也就是說實際上內部類和它所在的外部類實例對象是相關聯的,它不能脫離外部類實例而獨自存在,那麼咱們可能會好奇,它是怎麼樣和外部類進行相關聯的呢?實際上是編譯器在生成 Java 字節碼的時候經過給非靜態內部類添加構造方法,使其在進行實例化時獲得外部類的引用。ide
既然構建內部類時須要持有外部類對象的引用,那麼要想建立內部類對象就要使用外部類的對象來建立該內部類對象,以下:函數
public class OuterClass {
public class Inner {}
public static void main(String[] args) {
OuterClass out = new OuterClass();
OuterClass.Inner in = out.new Inner();
// 也可使用這種方式進行建立
Inner oin = out.new Inner();
}
}
複製代碼
當咱們不想內部類對象與其外部類對象之間有聯繫的時候,咱們能夠將內部類聲明爲 static,這樣它變成了靜態內部類,既然沒有和外部類對象有任何相關聯,因此它也不須要再依賴與外部類對象,這樣它也不能訪問外部類的非靜態成員,只可以訪問外部類的靜態成員,此外靜態內部類和非靜態內部類在建立時也稍有區別:學習
// OuterClass 爲外部類,類含有靜態內部類 S 以及非靜態內部類 I
OuterClass out = new OuterClass();
// 建立靜態內部類
out.S staticClass = out.S();
// 建立非靜態內部類
out.I in = out.new I();
複製代碼
這裏對靜態內部類和非靜態內部類作個總結:spa
若是一個內部類只在一個方法中使用,那麼咱們就能夠將這個類定義在方法內部,這種內部類被稱爲局部內部類,其做用域也僅限於該方法區內,以下:線程
public class OuterClass {
public void show() {
System.out.println("外部類方法");
}
public void showFunctionClass() {
class FunctionClass {
private void show() {
System.out.println("我是局部內部類");
}
}
FunctionClass FunctionClass = new FunctionClass();
FunctionClass.show();
}
public static void main(String[] args) {
OuterClass out = new OuterClass();
out.show();
out.showFunctionClass();
}
}
// 運行結果:
//外部類方法
//我是局部內部類
複製代碼
此外,局部內部類注意事項以下:code
匿名內部類是沒有類名的局部類,匿名內部類使得類的定義和實例化同時進行,因此一般用來進行簡化代碼編寫,而因爲它沒有類名也就不存在構造方法,下面經過兩個小實驗來學習匿名內部類的使用:cdn
public interface Person {
public void eat();
}
public class Child implements Person {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("eat...");
}
public static void main(String[] args) {
Child child = new Child();
child.eat();
}
}
複製代碼
這是沒有使用匿名內部類的普通寫法,先實現接口再重寫其中的方法,最後再實例化對象並調用方法,前面咱們說到匿名內部類能夠簡化代碼,那接下來看一樣的例子用匿名內部類怎麼來寫:
public class Child {
public static void main(String[] args) {
new Person() {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("eat...");
}
}.eat();
}
}
複製代碼
這樣引入匿名內部類直接就將接口中的方法進行重寫,就省略了一個類的編寫,因此只要是一個類是抽象類或者是一個接口,那麼其子類方法或接口方法均可以使用匿名內部類來實現
,匿名內部類經常使用的典型場景是使用 Thread 類或者 Runnable 接口來實現多線程。此外,還須要注意的是,匿名內部類若是使用一個在其外部定義的對象時,編譯器會要求該變量必須是 final,緣由即是要保持參數的一致性。
到這裏,咱們大概搞清楚內部類的相關知識點,其中在《Thinking in Java》一書中做者說到內部類最吸引人的緣由是:
每一個內部類都能獨立地繼承自一個(接口的)實現,因此不管外圍類是否已經繼承了某個(接口的)實現,對於內部類都沒有影響。
看到這兒,我想說的是大師就是大師,說的我都一臉懵逼了(太菜了),總結了下仍是有下面幾點:
參考資料: 《Thinking in Java》
- 咱們正在招募小夥伴,有興趣的小夥伴能夠把簡歷發到 app@talkmoney.cn,備註:來自掘金社區
- 詳情能夠戳這裏--> 廣州蘆葦信息科技