Java HashMap源码解析

1. HashMap内存储的元素是Entry,并且Entry是按照链表的形式来存储的。
transient Entry<K,V>[] table; // 用数组来存储,它的原理是每个数组的元素都是一个链表头



Entry的定义如下:
static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
}


2. get(Object key)方法解读
    public V get(Object key) {
        // 对key进行判空
        if (key == null)
            return getForNullKey();
        // 根据key找Entry
        Entry<K,V> entry = getEntry(key);

        return null == entry ? null : entry.getValue();
    }


 final Entry<K,V> getEntry(Object key) {
        //计算hash值
        int hash = (key == null) ? 0 : hash(key);
        // 根据hash值来查找在数组中的下标位置,然后沿着链表进行查找
        for (Entry<K,V> e = table[indexFor(hash, table.length)];
             e != null;
             e = e.next) {
            Object k;
            if (e.hash == hash &&
                ((k = e.key) == key || (key != null && key.equals(k))))
                return e;
        }
        return null;
    }



3. put(key,value)方法解读
  public V put(K key, V value) {
        // 对key进行判空处理
        if (key == null)
            return putForNullKey(value);
        // 计算hash值
        int hash = hash(key);
        // 查找在数据中的位置,然后沿着链表查找 ,如果有相同的值就覆盖,没有就加一个entry
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }

        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }



4.常见的参数设置
  默认大小是16
 static final int DEFAULT_INITIAL_CAPACITY = 16;


  当容量超过16时,就会扩容,然后会重新计算hash值,所以尽量在初始化的时候指定大小。

5. hashmap vs hashtable
   1)hashmap 是允许存储空值的,然hashtable是不允许的;
   2)初始化的大小不一样,hashmap是16,hashtable是11;
   3)hash的计算公式是不一样的;
   4) hashtable是线程安全的,而hashmap不是线程安全的。hashtable是怎么来保证线程安
      全的呢?(有些人看了一些面试宝典之类的,只是记住了这个结论)
     
      // 使用synchronized 来实现线程安全的
      public synchronized V put(K key, V value) {
        // Make sure the value is not null(不能为空的)
        if (value == null) {
            throw new NullPointerException();
        }
        ..
      }
      

猜你喜欢

转载自gaofulai1988.iteye.com/blog/2262394