這是一篇對Java Nested Class基礎知識的復習,也是掌握Java 8 Lambda原理的基礎。能力有限,希望能把嵌套類的相關內容說清楚。
嵌套類 Nested Class就是在一個class定義的內部定義另外一個類。
分類
Java中一般規(guī)定類的定義文件中只能定義一個Public Class,并且公有類名需要和類的物理文件名保持一致,不然編譯器會報錯。這個是Java的基本原則。
有些代碼組織會希望將這個公有類密切相關的類,與共有類放在一起。那么這個時候可以選擇:
- 在同一個文件中,定義包私有類,或私有類。也就是說在Public文件外定義類。
- 在公有類內部,再定義一個類。
第二種方式定義的類就是本文的主題,嵌套類(Nested Class)!
嵌套類能夠在任意的代碼塊Block中嵌套,通常情況下嵌套的范圍主要是2類:
- 在Public Class范圍內嵌套,換句話說就是一個類的定義作為類的Member。
- 在靜態(tài)塊、方法、條件判斷或者循環(huán)代碼塊中嵌套,換句話說就是代碼塊中的一個Variable。
對于第一種嵌套類,可以增加訪問限定符 public, protected, private 來修飾允許訪問范圍,也可以增加static關鍵詞;而第二種嵌套類則不能加任何的限定符。
對于加了static的嵌套類,則稱為靜態(tài)嵌套類;對于沒加static的嵌套類,則稱為非靜態(tài)嵌套類,又經常被稱為內部類(inner class)。
總結靜態(tài)嵌套類和內部類的區(qū)別,如下表:
| 靜態(tài)嵌套類 | 內部類 | |
|---|---|---|
| 生命周期 | 獨立于被嵌套類 | 依賴被嵌套類,只有在被嵌套類實例化后才可使用 |
| 訪問權限 | 不能訪問被嵌套類的成員 | 能夠訪問被嵌套類的任何成員,包含private |
| 能否擁有靜態(tài)成員 | 可以 | 不能 |
下面就每一個區(qū)別分別舉幾個例子說明:
生命周期
靜態(tài)嵌套類
public class Car {
private String vendorName;
private Tier[] tiers;
public Car(String vendorName, Tier tier) {
this.vendorName = vendorName;
Tier[] tiers = new Tier[4];
for (int i = 0; i < 4; i++) {
tiers[i] = tier.clone();
}
}
private static class Tier {
private int size;
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public Tier(int size) {
this.size = size;
}
protected Tier clone() {
return new Tier(this.getSize());
}
}
@Override
public String toString() {
return "Car{" +
"vendorName='" + vendorName + '\'' +
", tiers=" + Arrays.toString(tiers) +
'}';
}
public static void main(String[] args) {
Car car = new Car("Toyota", new Tier(17));
}
}
非靜態(tài)嵌套類
內部類
局部本地類 (local classes)
匿名類(anonymous classes)
Java 中匿名類——Lambda
inner class能訪問嵌套類的屬性,包括private
static nested class不能訪問嵌套類的成員
static nested class 的實例可以脫離外部類的生命周期獨立存在,通過 OutterClass.StaticInnerClass instantce = new OutterClass.StaticInnerClass();來創(chuàng)建實例
inner class的實例無法脫離外部類的生命周期獨立存在,要實例化一個inner class,必須先實例化相應的outer class,使用以下語法實例化inner class:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
inner class不能生命任何的靜態(tài)成員
inner class 的兩種特殊類型 local classes anonymous classes
local class是定義在代碼塊內部的,經常會出現(xiàn)在方法體內部。local class可以訪問類的成員。local class也可以訪問塊的本地變量,不過要求本地變量一定要是final的。因為會捕獲(capture)相應的值(captrued variable)在Java8開始,本地變量可以訪問effectively final的變量,翻譯為等價final可能比較合適,就是初始化時候從來不改變的值,編譯器會等同于final。java 8 開始,方法的本地類也可以訪問方法的參數(shù)。shadowing規(guī)則同inner class的shadow規(guī)則
不能在塊內定義接口,因為接口天然是靜態(tài)的。實例方法不是一個靜態(tài)的上下文。local cass內部不能定義static方法,只能定義static的常量
匿名類anonymous class與local class類似,只是沒有名稱。如果類只使用一次,可以使用匿名類。如果說Local class是類聲明,那么匿名類就是表達式
訪問規(guī)則:
匿名類可以訪問外部類的成員
匿名類不能訪問非final或effectively final的本地變量
匿名類內部的變量生命將屏蔽所有外部的同名變量。通過this, ClassName.this進行訪問
同local class,匿名類的成員也有限制:
不能聲明靜態(tài)的方法或接口
能夠擁有常量的靜態(tài)成員
匿名類內可以生命:字段、另外的方法、實例初始化器?,本地類。但不能聲明構造器(因為沒有名字)
如果匿名類只有一個方法,那么在Java 8中可以使用 Lambda表達式替代
java.util.function
inner class 同名變量的查找策略
method parameter, this.variableName(inner class), OuterClassName.this.variableName.
inner classes的序列化將遇到很大挑戰(zhàn)。不同的編譯器實現(xiàn)將影響代碼的可移植性,因為inner class的構造器是編譯器生成的。