你能自己实现一个 HashMap 吗
六个字段,十四个方法
可见性 | 类型 | 名称 | 描述 |
---|
private | Node<K, V>[] | buckets | 哈希桶数组 |
private | int | size | 当前键值对数量 |
static | final int | DEFAULT_CAPACITY | 默认初始容量(16) |
static | final float | LOAD_FACTOR | 负载因子(0.75) |
static | final int | MAX_CAPACITY | 最大容量(2^30) |
private | static class Node<K,V> | Node | 节点类,作为桶中链表节点 |
可见性 | 返回类型 | 方法名 | 参数 | 功能描述 |
---|
public | - | MyHashMap() | 无 | 无参构造函数 |
public | - | MyHashMap(int) | capacity | 有参构造,指定初始容量 |
private | int | tableSizeFor | int cap | 向上取最近的 2 的幂 |
private | int | hash | Object key | 高位扰动计算 hash 值 |
private | int | getIndex | Object key, int length | 获取桶索引 |
public | void | put | K key, V value | 添加键值对 |
private | void | putVal | K key, V value, Node<K, V>[] table | 实际执行 put 操作 |
private | void | resize | 无 | 扩容 |
private | void | rehash | Node<K, V>[] oldBuckets, newBuckets | 重新哈希,迁移旧数据到新桶 |
public | V | get | K key | 根据 key 获取值 |
public | int | size | 无 | 获取键值对个数 |
public | boolean | containsKey | K key | 判断 key 是否存在 |
public | V | remove | K key | 删除 key 对应的节点 |
public | void | clear | 无 | 清空整个 Map |
class MyHashMap<K, V> {
static class Node<K, V> { private K key; private V value; private Node<K, V> next; public Node(K key, V value) { this.key = key; this.value = value; } public Node(K key, V value, Node<K, V> next) { this.key = key; this.value = value; this.next = next; } }
static final int DEFAULT_CAPACITY = 16;
static final float LOAD_FACTOR = 0.75f; static final int MAX_CAPACITY = 1 << 30; private int size; private Node<K, V>[] buckets;
public MyHashMap() { buckets = new Node[DEFAULT_CAPACITY]; size = 0; }
public MyHashMap(int capacity) { if (capacity <= 0) { throw new IllegalArgumentException("Capacity must be greater than 0"); }
int cap = tableSizeFor(capacity); buckets = new Node[cap]; size = 0; } private int tableSizeFor(int cap) { int n = cap - 1; n |= n >>> 1; n |= n >>> 2; n |= n >>> 4; n |= n >>> 8; n |= n >>> 16; return (n < 0) ? 1 : (n >= MAX_CAPACITY) ? MAX_CAPACITY : n + 1; } private int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); }
private int getIndex(Object key, int length) { return hash(key) & (length - 1); }
public void put(K key, V value) { if (size >= buckets.length * LOAD_FACTOR) { resize();
} putVal(key, value, buckets); }
private void putVal(K key, V value, Node<K, V>[] table) { int index = getIndex(key, table.length); Node<K, V> node = table[index];
if (node == null) { table[index] = new Node<>(key, value); size++; return; }
while (node != null) { if (node.key.hashCode() == key.hashCode() && (node.key == key || node.key.equals(key))) { node.value = value; return; } node = node.next; }
Node<K, V> newNode = new Node<>(key, value, table[index]); table[index] = newNode; size++; }
private void resize() { Node<K, V>[] newBuckets = new Node[buckets.length * 2]; rehash(buckets, newBuckets); buckets = newBuckets; }
private void rehash(Node<K, V>[] oldBuckets, Node<K, V>[] newBuckets) { for (int i = 0; i < oldBuckets.length; i++) { if (oldBuckets[i] == null) { continue; } Node<K, V> node = oldBuckets[i]; while (node != null) { putVal(node.key, node.value, newBuckets); node = node.next; } oldBuckets[i] = null; } }
public V get(K key) { int index = getIndex(key, buckets.length); if (buckets[index] == null) { return null; } Node<K, V> node = buckets[index]; while (node != null) { if (node.key.hashCode() == key.hashCode() && (node.key == key || node.key.equals(key))) { return node.value; } node = node.next; } return null; }
public int size() { return size; }
public boolean containsKey(K key) { int index = getIndex(key, buckets.length); Node<K, V> node = buckets[index]; while (node != null) { if (node.key.hashCode() == key.hashCode() && (node.key == key || node.key.equals(key))) { return true; } node = node.next; } return false; } int index = getIndex(key, buckets.length); Node<K, V> node = buckets[index]; Node<K, V> prev = null; while (node != null) { if (node.key.hashCode() == key.hashCode() && (node.key == key || node.key.equals(key))) { if (prev == null) { buckets[index] = node.next; } else { prev.next = node.next; } size--; return node.value; } prev = node; node = node.next; } return null;
public void clear() {
for (int i = 0; i < buckets.length; i++) { buckets[i] = null; } size = 0; }
}