與欄位、方法類似,Java 允許類別作為其他類別成員。本文將巢狀類別分為四類:巢狀頂層類別、成員內部類別、區域內部類別、匿名內部類別,詳細說明各類型特性、存取規則與最佳實務。
Java 非必須支援類別巢狀,但至少有兩大優勢:
Employee.JobIterator 與 JobIterator 介面可共存)在頂層類別中宣告類別並在前加 static 修飾符。如靜態欄位/方法般與實例無關——無法存取外部類別實例成員(欄位/方法)。但可宣告自身實例欄位、建立自身實例。
class TopLevelClass {
static int staticField;
int instanceField;
static class NestedTopLevelClass {
static { System.out.println("Can access staticField " + staticField); }
{ System.out.println("Can access staticField " + staticField); }
}
}
編譯產生 TopLevelClass$NestedTopLevelClass.class。可多層巢狀,內層欄位會遮蔽外層同名欄位。
巢狀類別宣告不加 static。可同時存取外部類別靜態與實例成員。範例:Employee 類別中巢狀 JobIterator 直接存取 private Job[] jobs,無需建構子傳遞陣列參考,原始碼更清晰。
class Employee {
private String name;
private Job[] jobs;
Employee(String name, Job[] jobs) { this.name = name; this.jobs = jobs; }
String getName() { return name; }
JobIterator getJobIterator() { return new JobIterator(); }
class JobIterator {
private int jobIndex = 0;
public boolean hasMoreJobs() { return jobIndex < jobs.length; }
public Object nextJob() { return !hasMoreJobs() ? null : jobs[jobIndex++]; }
}
}
存取語法:Employee.JobIterator eji = e.getJobIterator(); 編譯產生 Employee$JobIterator.class。
在任意程式碼區塊(大括號內)宣告類別——方法內、if 區塊內等。除存取外部類別實例/類別成員外,可存取方法參數與區域變數(必須為 final)。編譯器為區域內部類別生成合成欄位儲存 final 區域變數副本,方法返回後區域變數消失,但內部類別實例仍持有副本引用可繼續存取。
static Enumeration enumerator(final Object[] array) {
class LocalInnerClass implements Enumeration {
private int index = 0;
public boolean hasMoreElements() { return index < array.length; }
public Object nextElement() { return array[index++].toString(); }
}
return new LocalInnerClass();
}
final 關鍵字確保兩物件不共享存取同一非 final 變數避免同步複雜度。基本型別區域變數會被編譯器以常數取代。
無名稱區域內部類別。宣告時必須同時建立實例。適用於短小、無需類別名稱、減少命名衝突的場合。無法宣告建構子(建構子需類別名稱),但可使用實例初始化區塊執行自定義初始化。編譯器以整數命名(如 OuterClass$1.class)。
new Farmer("Jane Doe") {
private String count;
{ // 實例初始化區塊
if (args.length == 1) count = args[0];
}
void occupation() {
if (count == null)
System.out.println("Farmer " + name + " milks cows");
else
System.out.println("Farmer " + name + " milks " + count + " cows");
}
}.occupation();
匿名內部類別最常見實戰用途:簡化 GUI 事件處理(滑鼠移動、按鈕點擊等)。範例:視窗關閉事件處理。
Frame f = new Frame("Anonymous Inner Class Demo");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
f.setSize(300, 100);
f.setVisible(true);
WindowAdapter 實作 WindowListener 所有方法(空實作),匿名內部類別擴展並覆寫 windowClosing,調用 System.exit(0) 終止程式。開發 GUI 事件處理時將頻繁使用匿名內部類別。
| 類型 | 宣告位置 | 存取外部成員 | 存取區域變數/參數 | 典型用途 |
|---|---|---|---|---|
| 巢狀頂層類別 | 類別內、static | 僅靜態 | 否 | 邏輯分組、命名空間管理 |
| 成員內部類別 | 類別內、非 static | 靜態+實例 | 否 | 迭代器、與外部實例緊密相關的行為 |
| 區域內部類別 | 方法/區塊內 | 靜態+實例 | 是 | 實作介面返回、需捕捉區域變數 |
| 匿名內部類別 | 運算式中 | 靜態+實例 | 是 | 事件處理、一次性介面實作 |
巢狀類別不僅讓原始碼清晰(在管理物件附近宣告類別),亦減少同層級類別命名衝突。掌握四類型特性與存取規則,能寫出更強大、更易維護的 Java 程式。