前注:本文介紹的HashMap並非Java類庫的實現。而是根據哈希表知識的一個實現。
上文介紹了開放地址法實現HashTable,它的缺點是對hashCode映射為地址后如果出現重復地址,則會占用其他元素的位置。這樣HashTable存儲容量有限,而且不便於算法理解。本文介紹鏈地址法實現HashMap。
鏈地址法內部仍然有一個數組,但區別與開放地址法,該數組存儲的是一個鏈表的引用。當根據hashCode計算出數組下表后,對元素的增刪查改都是在該數組元素所指向的鏈表上完成的。這就解決了hashCode重復的問題。因為,當hashCode重復,多個元素對應同一個地址,但元素實際存儲的位置在數組對應的鏈表上。所以相同hashCode的不同元素可以存儲在同一位置。
下面是代碼實現:

package org.lyk.interfaces; public interface IMap<K,V> { /** * 根據key值增加一個value,如果key重復,則新元素替換舊元素 * @param key * @param value */ public void put(K key, V value); /** * 根據key值移除value * @param key * @return */ public boolean remove(K key); public V get(K key); public boolean contains(K key); public void replace(K key, V value); }

package org.lyk.impl; import java.util.ArrayList; import org.lyk.interfaces.IMap; public class HashMap<K,V> implements IMap<K, V> { private class KeyValue { private K key; private V value; public KeyValue(K key, V value) { this.key = key; this.value = value; } public K getKey() { return key; } public void setKey(K key) { this.key = key; } public V getValue() { return value; } public void setValue(V value) { this.value = value; } } private int maxSize = 10; private Object[] table; public HashMap() { this.table = new Object[this.maxSize]; for(int i = 0; i < this.maxSize; i++) { this.table[i] = new java.util.ArrayList<KeyValue>(); } } @Override public void put(K key, V value) { int index = this.getIndex(key); KeyValue kv = this.find(key); if(kv == null) { ((java.util.List<KeyValue>)this.table[index]).add(new KeyValue(key, value)); } else { kv.setValue(value); } } @Override public boolean remove(K key) { int index = this.getIndex(key); java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index]; int listIndex = -1; for(KeyValue kv : kvs) { if(kv.key.equals(key)) { listIndex = kvs.indexOf(kv); } } if(listIndex != -1) { kvs.remove(listIndex); return true; } return false; } @Override public V get(K key) { KeyValue kv= this.find(key); if(kv != null) return kv.getValue(); else return null; } @Override public boolean contains(K key) { if(this.get(key) != null) return true; else return false; } @Override public void replace(K key, V value) { KeyValue kv = this.find(key); if(kv != null) { kv.setValue(value); } } private int getIndex(K key) { return Math.abs(key.hashCode())%this.maxSize; } private KeyValue find(K key) { int index = this.getIndex(key); java.util.List<KeyValue> kvs = (java.util.List<KeyValue>)this.table[index]; for(KeyValue kv : kvs) { if(kv.key.equals(key)) { return kv; } } return null; } }