Java HashMap简单实现原理的理解

jopen 10年前

正常情况下,Map的key和Value都可以用数组实现,一边ArrayList是key的keys,另一边是ArrayList value的values。

通过key获取value的方式是这样的values.get(keys.indexOf(key)).

然而,数组的长度是有限的。不符合map可以无限放入元素的要求。所以要对这个数组进行特殊的要求。

那就是同一个数组的index可以存放多个值,只是这些相同index的hascode值不同,这样就能把他们却别开了。同时也就实现无限个元素要求了(用数组实现主要是性能的优势)。那么要确定value就要计算hascode和数组下标。

数组不直接执行value的值,而是用equals()方法线性的查找;正常情况下这样的查找方式也会慢,但是只要hascode方法设计的合理,每个插槽将会只有少量的value.这样查找也就快很多;

import java.util.Map;    public class MapEntry<K,V> implements Map.Entry<K, V> {   private K key;   private V value;   public MapEntry(K key, V value) {    this.key = key;    this.value = value;   }   @Override   public K getKey() {    return key;   }   @Override   public V getValue() {    return value;   }   @Override   public V setValue(V value) {    V result = this.value;    this.value =value;    return result;   }   @Override   public int hashCode() {    return (key == null ? 0:key.hashCode())^(value == null ? 0: value.hashCode());   }   @Override   public boolean equals(Object obj) {    if(!(obj instanceof MapEntry)) {     return false;    }    MapEntry me = (MapEntry)obj;    return (key ==null ? me.getKey() == null : key.equals(me.getKey())) &&      (value == null ? me.getValue()==null : value.equals(me.getValue()));   }   @Override   public String toString() {    return key+"="+value;   }  }



import java.util.AbstractMap;  import java.util.HashSet;  import java.util.LinkedList;  import java.util.ListIterator;  import java.util.Map;  import java.util.Set;    public class SimpleHashMap<K,V> extends AbstractMap<K, V> {   static final int SIZE = 997;   /**集合类型数组,数组的每个元素都是一个List集合类型**/   LinkedList<MapEntry<K, V>>[] buckets = new LinkedList[SIZE];   public V put(K key, V value) {    V oldValueV = null;    /**根据hascode对数组长度求模,计算得出应该放入数组的index位置**/    int index = Math.abs(key.hashCode())%SIZE;    if(buckets[index] == null) {     /**如果该下标下还没有集合,则创建**/     buckets[index] = new LinkedList<MapEntry<K, V>>();    }    LinkedList<MapEntry<K, V>> bucket = buckets[index];    /**把传进来的key和value封装为MapEntry类型**/    MapEntry<K, V> pair = new MapEntry<K, V>(key, value);    /**假设在该数组index下的机会里找不到与pair对应的值**/    boolean found = false;    ListIterator<MapEntry<K, V>> it = bucket.listIterator();    while(it.hasNext()) {     MapEntry<K, V> iPair = it.next();     if(iPair.getKey().equals(key)) {      /**如果已经存在,则替换掉**/      oldValueV = iPair.getValue();      it.set(pair);      found = true;      break;     }    }    if(!found) {     /**如果不存在,则把封装后的MapEntry对象加入的集合中**/     buckets[index].add(pair);    }    return oldValueV;   }   public V ge(Object key) {    /**已同样的方式计算出应该的index**/    int index = Math.abs(key.hashCode())%SIZE;    if(buckets[index]==null) {     /**对应的index里没有机会**/     return null;    }    for(MapEntry<K, V> iPair : buckets[index]) {     if(iPair.getKey().equals(key)) {      /**对该index下的机会进行查找,比较MapEntr的key值**/      return iPair.getValue();     }    }    return null;   }   @Override   public Set<Map.Entry<K, V>> entrySet() {    Set<Map.Entry<K, V>> set = new HashSet<Map.Entry<K,V>>();    for(LinkedList<MapEntry<K, V>> bucket : buckets) {     if(bucket == null) continue;     for(MapEntry<K, V> mpair : bucket) {      /**用2个for循环,遍历这个二维的集合,把遍历到的每个值放到Set里**/      set.add(mpair);     }    }    return set;   }   public static void main(String[] args) {    SimpleHashMap<String, String> mMap = new SimpleHashMap<String,String>();    mMap.put("YYY", "yyy");    mMap.put("QQQ", "qqq");    mMap.put("AAA", "aaa");    mMap.put("GGG", "ggg");    System.out.println(mMap);    System.out.println(mMap.get("GGG"));    System.out.println(mMap.entrySet());   }  }


摘自thinking in java