自定義一個簡易 Map 容器 MyContainer<K, V>,存儲鍵值對 (如英文名 → 中文名),核心要求:
Entry<K, V> 封裝鍵值對,實現數據與容器邏輯分離。Arrays.copyOf)。put(K, V)、get(K)、entries() (返回有效 Entry 數組/集合) 核心 API。Iterable<Entry<K,V>>,支持增強 for 循環遍歷。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
| 設計點 | 實現細節 | 優勢 |
|---|---|---|
| 靜態內部類 Entry | static 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) 觸發擴容。Serializable,自定義 writeObject/readObject。從零手寫容器,是深入理解 Java 集合框架設計哲學、泛型擦除、迭代器模式、動態陣列擴容、封裝與防禦性編程的最佳路徑!