Java 集合框架中 List 維護插入順序並允許重複元素,Map 則鍵值唯一且支持快速鍵查找。某些業務場景需要同時擁有這兩者特性:既要按索引訪問,又要按鍵快速查找,還要保持插入順序。由於 Java 不允許類同時實現 List 和 Map 兩個接口,本文實現了一個自定義 ListMap<K, V> 容器類,融合雙重功能。
List<Item> 存儲鍵值對,Item 為內部類封裝 key 和 valueput() 和 add() 方法通過遍歷檢查保證get(index) 按位置取值,get(key) 按鍵取值containsKey()、containsValue()、indexOfKey()、indexOfValue() 等專用方法
package myCollections;
import java.util.*;
/**
* 兼具 List 和 Map 功能的容器類
*/
@SuppressWarnings({"unchecked"})
public class ListMap<K, V> {
private List<Item> values = new ArrayList<>();
// === 基礎屬性 ===
public int size() { return values.size(); }
public boolean isEmpty() { return values.isEmpty(); }
// === 迭代與轉換 ===
public Iterator<V> iterator() { return values().iterator(); }
public V[] toArray() {
Object[] arr = new Object[values.size()];
for (int i = 0; i < values.size(); i++) arr[i] = values.get(i).value;
return (V[]) arr;
}
// === Map 風格查詢 ===
public boolean containsKey(K key) {
if (key == null) return false;
for (Item item : values) if (item.key.equals(key)) return true;
return false;
}
public boolean containsValue(V value) {
for (Item item : values) if (item.value.equals(value)) return true;
return false;
}
public V get(K key) {
for (Item item : values) if (item.key.equals(key)) return item.value;
return null;
}
public V put(K key, V value) {
for (Item item : values) {
if (item.key.equals(key)) {
V replaced = item.value;
item.value = value;
return replaced;
}
}
values.add(new Item(key, value));
return null;
}
public boolean remove(K key) {
for (Item item : values) {
if (item.key.equals(key)) return values.remove(item);
}
return false;
}
// === List 風格操作 ===
public V remove(int index) { return values.remove(index).value; }
public void clear() { values.clear(); }
public V get(int index) { return values.get(index).value; }
public V set(int index, V value) {
Item item = values.get(index);
V old = item.value;
item.value = value;
return old;
}
public void add(int index, K key, V value) {
if (containsKey(key)) throw new IllegalStateException("key already exists.");
values.add(index, new Item(key, value));
}
// === 索引查找 ===
public int indexOfValue(V value) {
for (int i = 0; i < values.size(); i++)
if (values.get(i).value.equals(value)) return i;
return -1;
}
public int indexOfKey(K key) {
if (key == null) return -1;
for (int i = 0; i < values.size(); i++)
if (values.get(i).key.equals(key)) return i;
return -1;
}
// === 子列表與視圖 ===
public ListMap<K, V> subList(int fromIndex, int toIndex) {
ListMap<K, V> map = new ListMap<>();
map.values.addAll(values.subList(fromIndex, toIndex));
return map;
}
public List<V> values() {
List<V> list = new ArrayList<>();
for (Item item : values) list.add(item.value);
return list;
}
public List<K> keys() {
List<K> list = new ArrayList<>();
for (Item item : values) list.add(item.key);
return list;
}
// === 排序與反轉 ===
public void sortKey() {
Collections.sort(values, (i1, i2) -> {
Comparable c1 = (Comparable) i1.key, c2 = (Comparable) i2.key;
if (c1 == null && c2 == null) return 0;
if (c1 == null) return -1;
if (c2 == null) return 1;
return c1.compareTo(c2);
});
}
public void sortValue() {
Collections.sort(values, (i1, i2) -> {
Comparable c1 = (Comparable) i1.value, c2 = (Comparable) i2.value;
if (c1 == null && c2 == null) return 0;
if (c1 == null) return -1;
if (c2 == null) return 1;
return c1.compareTo(c2);
});
}
public void reverse() { Collections.reverse(values); }
// === 內部類 ===
private class Item {
public K key;
public V value;
public Item(K key, V value) {
if (key == null) throw new NullPointerException("key cannot be null.");
this.key = key; this.value = value;
}
}
}
ListMap<String, Integer> scores = new ListMap<>();
scores.put("Alice", 95);
scores.put("Bob", 87);
scores.add(0, "Charlie", 92); // 插入到頭部
System.out.println(scores.get(0)); // 92 (按索引)
System.out.println(scores.get("Bob")); // 87 (按鍵)
System.out.println(scores.indexOfKey("Alice")); // 1
scores.sortKey(); // 按鍵排序
scores.sortValue(); // 按值排序
| 操作 | 時間複雜度 | 說明 |
|---|---|---|
| 按鍵查找/插入/刪除 | O(n) | 需線性掃描 |
| 按索引查找/修改 | O(1) | ArrayList 隨機訪問 |
| 遍歷/迭代 | O(n) | 順序訪問 |
適用場景:數據量較小(<1000)、頻繁按順序遍歷且偶爾按鍵查找、需要保持插入順序的鍵值對集合。大數據量高頻鍵查找場景建議使用 LinkedHashMap + 獨立 ArrayList 組合。
HashMap<K, Integer> 緩存鍵到索引映射,將鍵操作優化至 O(1)Collection<V> 和 Map<K, V> 接口以兼容標準庫Collections.synchronizedList 或 CopyOnWriteArrayList)這個 ListMap 實現雖簡單,卻精準解決了「有序鍵值對」這一特定需求,是理解集合框架設計權衡的優秀案例。