hashmap是基于hash算法实现的一个存储键值对的大型hash表,他本质上是一个entry类的数组,entry[],entry是hashmap的内部类,之所有使用内部类,是因为内部类可以使用所有的外部类所有变量,并且只用于外部类,期望对其他类不可见。我们来看一看entry的源码

static class Entry<K,V> implements Map.Entry<K,V> {  
 
        final K key;  
 
        V value;  
 
        Entry<K,V> next;  
 
        final int hash;  
 
  
 
        // 构造函数  
 
        Entry(int h, K k, V v, Entry<K,V> n) {  
 
            value = v;  
 
            next = n;  
 
            key = k;  
 
            hash = h;  
 
        }  
 
          
 
        // 返回key  
 
        public final K getKey() {  
 
            return key;  
 
        }  
 
  
 
        // 返回value  
 
        public final V getValue() {  
 
            return value;  
 
        }  
 
  
 
        // 设置value  
 
        public final V setValue(V newValue) {  
 
        V oldValue = value;  
 
            value = newValue;  
 
            return oldValue;  
 
        }  
 
  
 
        // 是否相同  
 
        public final boolean equals(Object o) {  
 
            // 如果o不是Map.Entry的实例,那么肯定不相同了  
 
            if (!(o instanceof Map.Entry))  
 
                return false;  
 
            // 将o转成Map.Entry  
 
            Map.Entry e = (Map.Entry)o;  
 
            // 得到key和value对比是否相同,相同则为true  
 
            Object k1 = getKey();  
 
            Object k2 = e.getKey();  
 
            if (k1 == k2 || (k1 != null && k1.equals(k2))) {  
 
                Object v1 = getValue();  
 
                Object v2 = e.getValue();  
 
                if (v1 == v2 || (v1 != null && v1.equals(v2)))  
 
                    return true;  
 
            }  
 
            // 否则为false  
 
            return false;  
 
        }  
 
  
 
        // hashCode  
 
        public final int hashCode() {  
 
            return (key==null   ? 0 : key.hashCode()) ^  
 
                   (value==null ? 0 : value.hashCode());  
 
        }  
 
  
 
        // 返回String  
 
        public final String toString() {  
 
            return getKey() + "=" + getValue();  
 
        }  
 
  
 
        // 使用该方法证明该key已经在该map中  
 
        void recordAccess(HashMap<K,V> m) {  
 
        }  
 
  
 
        // 该方法记录该key已经被移除了  
 
        void recordRemoval(HashMap<K,V> m) {  
 
        }  
 
    }  
 
  
 
    // 添加一个新的桶来保存该key和value  
 
    void addEntry(int hash, K key, V value, int bucketIndex) {  
 
    // 保存对应table的值  
 
    Entry<K,V> e = table[bucketIndex];  
 
        // 然后用新的桶套住旧的桶,链表  
 
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
 
        // 如果当前size大于等于阈值  
 
        if (size++ >= threshold)  
 
            // 调整容量  
 
            resize(2 * table.length);  
 
    }  
 
  
 
    // 新建一个桶,该方法不需要判断是否超过阈值  
 
    void createEntry(int hash, K key, V value, int bucketIndex) {  
 
    Entry<K,V> e = table[bucketIndex];  
 
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);  
 
        size++;  
 
    }

看到源码就清楚了,其实map其实是用的entry类的变量key,value分别用来存储键值对,然后next用于存储hash值相同的entry对象。看了源码这么久,我觉得hashmap最精彩的一部分就是利用key的hashcode来规定entry对象在entry[]里的位置,当两个key的hashcode相同时,当前数组的位置由于存储最新的entry类,然后用next存储老的entry,而这个老的entry类的next变量又可能存储一个entry类,这样不断递归就形成了链表。

hashmap重写了超类object中的hashmap,equal,tostring方法。因为key值是唯一的,而相同key的hashcode的值可能不同,需要我们重写.

我们再来看一看hashmap的put方法源码

    1. public V put(K key, V value) {  
    2. // 如果key为null使用putForNullKey来获取  
    3. if (key == null)  
    4. return putForNullKey(value);  
    5. // 使用hash函数预处理hashCode  
    6. int hash = hash(key.hashCode());  
    7. // 获取对应的索引  
    8. int i = indexFor(hash, table.length);  
    9. // 得到对应的hash值的桶,如果这个桶不是,就通过next获取下一个桶  
    10. for (Entry<K,V> e = table[i]; e != null; e = e.next) {  
    11.             Object k;  
    12. // 如果hash相同并且key相同  
    13. if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {  
    14. // 获取当前的value  
    15.                 V oldValue = e.value;  
    16. // 将要存储的value存进去  
    17.                 e.value = value;  
    18. this);  
    19. // 返回旧的value  
    20. return oldValue;  
    21.             }  
    22.         }  
    23.   
    24.         modCount++;  
    25.         addEntry(hash, key, value, i);  
    26. return null;  
    27.     }

                      hashmap新增一个键值对时,先计算key的hashcode值计算它在entry[]数组中的位置,如果位置没有被占用,直接把entry放在这个位置,如果这个位置上已经有值了,然后把当前位置的entry类的key,value变量值变为新添加的键值对,而next的entry放置老的key,value,而next再次放下一个的next的entry类的key,value,通过for循环逐渐附值。