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

Java 靜態內部類實現鍵值對容器:動態擴容、泛型化與迭代器模式完整實戰

     編輯:Java 綜合教學

Java 靜態內部類實現鍵值對容器:動態擴容、泛型化與迭代器模式完整實戰

需求場景

自定義一個簡易 Map 容器 MyContainer<K, V>,存儲鍵值對 (如英文名 → 中文名),核心要求:

  1. 使用靜態內部類 Entry<K, V> 封裝鍵值對,實現數據與容器邏輯分離。
  2. 底層採用動態陣列 存儲 Entry,默認容量 5,**滿載時 2 倍擴容** (Arrays.copyOf)。
  3. 提供 put(K, V)、get(K)、entries() (返回有效 Entry 數組/集合) 核心 API。
  4. 進階:實現 Iterable<Entry<K,V>>,支持增強 for 循環遍歷。

完整實現代碼 (JDK 8+)

import java.util.Arrays;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Objects;

public class MyContainer<K, V> implements Iterable<MyContainer.Entry<K, V>> {

    // ===== 靜態內部類:鍵值對封裝 =====
    public static class Entry<K, V> {
        private final K key;   // 鍵不可變 (Map 語義)
        private V value;       // 值可更新

        public Entry(K key, V value) {
            this.key = Objects.requireNonNull(key, "Key cannot be null");
            this.value = value;
        }
        public K getKey() { return key; }
        public V getValue() { return value; }
        public void setValue(V value) { this.value = value; }

        @Override public String toString() { return key + "=" + value; }
        @Override public boolean equals(Object o) {
            if (this == o) return true;
            if (!(o instanceof Entry)) return false;
            Entry<?,?> e = (Entry<?,?>) o;
            return Objects.equals(key, e.key) && Objects.equals(value, e.value);
        }
        @Override public int hashCode() { return Objects.hash(key, value); }
    }

    // ===== 容器核心字段 =====
    private static final int DEFAULT_CAPACITY = 5;
    private Entry<K, V>[] table; // Entry 陣列
    private int size = 0;       // 有效元素數

    @SuppressWarnings("unchecked")
    public MyContainer() {
        table = (Entry<K, V>[]) new Entry[DEFAULT_CAPACITY];
    }

    // ===== 核心 API =====

    /** 添加/更新鍵值對,返回舊值 (如有) */
    public V put(K key, V value) {
        Objects.requireNonNull(key);
        // 1. 查找是否存在
        for (int i = 0; i < size; i++) {
            if (Objects.equals(table[i].getKey(), key)) {
                V old = table[i].getValue();
                table[i].setValue(value);
                return old;
            }
        }
        // 2. 擴容檢查
        if (size >= table.length) {
            resize(table.length * 2);
        }
        // 3. 插入新 Entry
        table[size++] = new Entry<>(key, value);
        return null;
    }

    /** 獲取值 */
    public V get(K key) {
        for (int i = 0; i < size; i++) {
            if (Objects.equals(table[i].getKey(), key)) return table[i].getValue();
        }
        return null;
    }

    /** 返回有效 Entry 數組副本 (防禦性複製) */
    public Entry<K, V>[] entries() {
        return Arrays.copyOf(table, size);
    }

    public int size() { return size; }
    public boolean isEmpty() { return size == 0; }

    // ===== 私有擴容方法 =====
    @SuppressWarnings("unchecked")
    private void resize(int newCapacity) {
        table = Arrays.copyOf(table, newCapacity);
    }

    // ===== 實現 Iterable:支持 for (Entry e : container) =====
    @Override
    public Iterator<Entry<K, V>> iterator() {
        return new Iterator<>() {
            private int cursor = 0;
            @Override public boolean hasNext() { return cursor < size; }
            @Override public Entry<K, V> next() {
                if (!hasNext()) throw new NoSuchElementException();
                return table[cursor++];
            }
        };
    }

    // ===== 測試驗證 =====
    public static void main(String[] args) {
        MyContainer<String, String> container = new MyContainer<>();
        container.put("jack", "傑克");
        container.put("jay", "周傑倫");
        container.put("john", "約翰");
        container.put("rose", "羅斯");
        container.put("jack", "張三"); // 更新測試

        System.out.println("=== 方式1: entries() 數組遍歷 ===");
        for (Entry<String, String> e : container.entries()) {
            System.out.println(e.getKey() + " → " + e.getValue());
        }

        System.out.println("\n=== 方式2: 增強 for 循環 (Iterable) ===");
        for (Entry<String, String> e : container) {
            System.out.println(e); // 調用 Entry.toString()
        }

        System.out.println("\n=== 獲取單個值 ===");
        System.out.println("jay = " + container.get("jay"));
        System.out.println("不存在鍵 = " + container.get("unknown"));
    }
}

輸出結果

=== 方式1: entries() 數組遍歷 ===
jack → 張三
jay → 周傑倫
john → 約翰
rose → 羅斯

=== 方式2: 增強 for 循環 (Iterable) ===
jack=張三
jay=周傑倫
john=約翰
rose=羅斯

=== 獲取單個值 ===
jay = 周傑倫
不存在鍵 = null

設計亮點與最佳實踐總結

設計點實現細節優勢
靜態內部類 Entrystatic class Entry<K,V>,不持有外部類引用內存效率高,可獨立使用,語義清晰
泛型化MyContainer<K,V>、Entry<K,V>類型安全,編譯期檢查,消除強轉
鍵不可變final K key,構造器注入符合 Map 語義,防止鍵修改導致查找失效
動態擴容size >= length → resize(2x),Arrays.copyOf均攤 O(1) 插入,平衡空間與性能
防禦性複製entries() → Arrays.copyOf(table, size)避免外部修改內部陣列,破壞封裝
實現 Iterable匿名內部類 Iterator,cursor 遍歷支持增強 for、Stream API、Lambda 表達式
null 鍵防護Objects.requireNonNull(key)快速失效,避免 NPE 隱患

進階擴展方向

  • 哈希分桶:引入 hash(key) & (n-1) 定位桶位,鏈表/紅黑樹解決衝突,實現 O(1) 平均查找 (即 HashMap 核心)。
  • 負載因子與擴容閾值:size > threshold (capacity * loadFactor) 觸發擴容。
  • 併發安全:分段鎖 (Segment) 或 CAS + synchronized (JDK 8 ConcurrentHashMap)。
  • 序列化支持:實現 Serializable,自定義 writeObject/readObject。

從零手寫容器,是深入理解 Java 集合框架設計哲學、泛型擦除、迭代器模式、動態陣列擴容、封裝與防禦性編程的最佳路徑!

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