內部類 定義在另一個類別內部。作為方法參數時,表示**方法需要特定外部類實例上下文的內部類實例**,常用於回調、事件監聽、建構者模式、策略模式等場景。
| 類型 | 語法 | 建立方式 | 訪問外部成員 | 典型參數用法 |
|---|---|---|---|---|
| 非靜態內部類 (Member Inner Class) | `class Outer { class Inner {} }` | `outer.new Inner()` | 可直接訪問外部實例所有成員 (含 private) | 回調、事件處理器、需持有外部引用 |
| 靜態內部類 | `class Outer { static class Inner {} }` | `new Outer.Inner()` | 僅能訪問外部靜態成員 | 資料傳輸物件 (DTO)、Builder、獨立邏輯封裝 |
| 區域內部類 | 定義在方法/區塊內 | 僅在該作用域內 `new LocalClass()` | 訪問 final/Effectively final 區域變數 | 方法內臨時邏輯封裝、策略實現 |
| 匿名內部類 | `new Interface() { ... }` 或 `new Class() { ... }` | 就地建立實例 | 同區域內部類 | 一次性實現介面/抽象類 (舊版 Java 常見) |
// 外部類:列表視圖
public class ListView {
// 靜態內部類:條目資料模型 (無需持有 ListView 引用)
public static class ListItem {
public String title;
public String description;
public ListItem(String title, String desc) {
this.title = title;
this.description = desc;
}
}
private List items = new ArrayList<>();
// 方法參數為內部類 ListItem
public void addItem(ListItem item) {
if (item != null) {
items.add(item);
System.out.println("新增條目: " + item.title);
}
}
public void render() {
for (ListItem item : items) {
System.out.printf("[%s] %s\n", item.title, item.description);
}
}
}
// 使用端
public class Main {
public static void main(String[] args) {
ListView listView = new ListView();
// 直接建立靜態內部類實例傳入
listView.addItem(new ListView.ListItem("標題 1", "描述內容 1"));
listView.addItem(new ListView.ListItem("標題 2", "描述內容 2"));
listView.render();
}
}
public class EventManager {
// 非靜態內部類:事件監聽器,需持有 EventManager 引用以回呼
public class Listener {
private String eventName;
public Listener(String name) { this.eventName = name; }
public void onEvent(String data) {
System.out.println("[" + eventName + "] 收到: " + data);
// 可直接存取 EventManager 私有方法/欄位
EventManager.this.internalLog(eventName, data);
}
}
private void internalLog(String event, String data) {
// 內部日誌邏輯
}
// 方法參數為非靜態內部類
public void register(Listener listener) {
// 儲存監聽器...
System.out.println("註冊監聽: " + listener.eventName);
}
public Listener createListener(String name) {
return new Listener(name); // 等同 this.new Listener(name)
}
}
// 使用
EventManager mgr = new EventManager();
EventManager.Listener listener = mgr.createListener("UserLogin"); // 必須透過外部實例建立
mgr.register(listener);
public class HttpRequest {
private final String url;
private final String method;
private final Map headers;
private final String body;
private HttpRequest(Builder builder) {
this.url = builder.url;
this.method = builder.method;
this.headers = builder.headers;
this.body = builder.body;
}
// 靜態內部類 Builder
public static class Builder {
private String url;
private String method = "GET";
private Map headers = new HashMap<>();
private String body;
public Builder url(String url) { this.url = url; return this; }
public Builder method(String method) { this.method = method; return this; }
public Builder header(String k, String v) { headers.put(k, v); return this; }
public Builder body(String body) { this.body = body; return this; }
// 建構方法參數為 Builder 內部類自身 (鏈式調用)
public HttpRequest build() {
if (url == null) throw new IllegalStateException("URL required");
return new HttpRequest(this);
}
}
}
// 使用
HttpRequest req = new HttpRequest.Builder()
.url("https://api.example.com/users")
.method("POST")
.header("Content-Type", "application/json")
.body("{\"name\":\"John\"}")
.build();
public interface SortStrategy {
void sort(int[] arr);
}
public class Sorter {
public void sort(int[] arr, SortStrategy strategy) { // 參數為介面,實際傳入內部類實現
strategy.sort(arr);
}
}
// 使用:匿名內部類實現策略 (Java 7 風格)
Sorter sorter = new Sorter();
sorter.sort(new int[]{3,1,2}, new SortStrategy() {
@Override public void sort(int[] arr) {
// 快速排序實作...
Arrays.sort(arr); // 簡化
}
});
// Java 8+ Lambda 替代 (更簡潔)
sorter.sort(new int[]{3,1,2}, arr -> Arrays.sort(arr));
內部類作為方法參數核心在於 **「封裝上下文相關行為或資料」**。
- **靜態內部類** = 獨立資料/邏輯容器 (Builder、DTO)
- **非靜態內部類** = 需外部實例協作的回調/監聽器
- **匿名/區域內部類** = 一次性策略/邏輯實現 (現代 Java 用 Lambda)
理解四種內部類的生命週期、外部引用持有關係,是設計乾淨 API 的關鍵。