首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 內部類作為方法參數:概念解析、實戰範例與設計模式應用

     編輯:程式設計綜合問答

核心概念

內部類 定義在另一個類別內部。作為方法參數時,表示**方法需要特定外部類實例上下文的內部類實例**,常用於回調、事件監聽、建構者模式、策略模式等場景。

四種內部類與參數傳遞差異

類型語法建立方式訪問外部成員典型參數用法
非靜態內部類 (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 常見)

實戰範例 1:ListView 與 ListItem (原回答場景)

// 外部類:列表視圖
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();
    }
}

實戰範例 2:非靜態內部類作為回調 (需外部實例)

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);

實戰範例 3:Builder 模式 (靜態內部類)

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();

實戰範例 4:策略模式 (區域/匿名內部類)

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));

設計考量與最佳實務

  • 靜態優先:不需外部實例上下文時,**務必加 `static`**,避免隱性持有外部引用導致記憶體洩漏
  • 序列化風險:非靜態內部類實例序列化會連帶序列化外部實例,慎用於分散式系統
  • Lambda 替代:單一抽象方法介面 (SAM) 參數,**優先用 Lambda**,匿名內部類為舊版相容
  • 命名慣例:內部類名稱通常為 `OuterClass.InnerClass` (如 `Map.Entry`、`HttpRequest.Builder`)

總結

內部類作為方法參數核心在於 **「封裝上下文相關行為或資料」**。
- **靜態內部類** = 獨立資料/邏輯容器 (Builder、DTO)
- **非靜態內部類** = 需外部實例協作的回調/監聽器
- **匿名/區域內部類** = 一次性策略/邏輯實現 (現代 Java 用 Lambda)
理解四種內部類的生命週期、外部引用持有關係,是設計乾淨 API 的關鍵。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved