java源码解读之HashMap

来源:互联网 发布:安安软件站爆枪英雄 编辑:程序博客网 时间:2024/04/29 09:41

1:首先下载openjdk(http://pan.baidu.com/s/1dFMZXg1),把源码导入eclipse,以便看到jdk源码

           Windows-Preferences-Java-Installed JREs,选中相应的jdk,Edit-选中rt.jre,点击Source Attachment,在弹出的菜单中选中单选按钮External location,把下载好的源码导进来.(如图)


2:HashMap概述

    HashMap是基于哈希表的Map接口的非同步实现,允许使用null值和null键,但不保障顺序不变

3:HashMap的数据结构

    HashMap实际是一个 链表散列 的数据结构,即数组和链表的结合体


    如图:HashMap底层是一个数组结构,数组的每一项又是一个链表.

   Map<Object,Object> hashMap = new HashMap<>();//其中默认加载因子是0.75f,默认初始容量16,table是一个长度为16的数组.


4:HashMap的存取实现

        public V put(K key, V value) {

//当key为null时,调用putForNullKey(value);把value放入数组第一个位置

        if (key == null)
            return putForNullKey(value);

//根据key的hashCode重新计算hash值

        int hash = hash(key.hashCode());

//搜索制定的hash值在table中的索引

        int i = indexFor(hash, table.length);

//如果i索引处的entry不为null,通过循环不断遍历e的下一个元素

        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;
            }
        }
//如果i索引处的Entry为null,表明此处还没有Entry
        modCount++;

//将K,V增加到i所引处

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

从上面的源代码中可以看出:当我们往HashMap 中put 元素的时候,先根据key 的hashCode 重新计算hash 值,根据hash 值得到这个元素在数组中的位置(即下标),如
果数组该位置上已经存放有其他元素了,那么在这个位置上的元素将以链表的形式存放,新加入的放在链头,最先加入的放在链尾。如果数组该位置上没有元素,就直接将该元素放到此数组中的该位置上。

addEntry(hash, key, value, i)方法根据计算出的hash 值,将key-value 对放在数组table的i 索引处.addEntry 是 HashMap 提供的一个包访问权限的方法,代码如下:

void addEntry(int hash, K key, V value, int bucketIndex) {
 // 获取指定 bucketIndex 索引处的 Entry
 Entry<K,V> e = table[bucketIndex];
 // 将新创建的 Entry 放入 bucketIndex 索引处,并让新的 Entry 指向原来的 Entry
 table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
 // 如果 Map 中的 key-value 对的数量超过了极限
 if (size++ >= threshold)
 // 把 table 对象的长度扩充到原来的2 倍。
 resize(2 * table.length);
 }

当系统决定存储HashMap 中的key-value 对时,完全没有考虑Entry 中的value,仅仅只是根据key 来计算并决定每个Entry 的存储位置。我们完全可以把 Map 集合中的 value 当
成 key 的附属,当系统决定了 key 的存储位置之后,value 随之保存在那里即可。

hash(int h)方法根据key 的hashCode 重新计算一次散列。此算法加入了高位计算,防止低位不变,高位变化时,造成的hash 冲突。

static int hash(int h) {
 h ^= (h >>> 20) ^ (h >>> 12);
 return h ^ (h >>> 7) ^ (h >>> 4);
 }



------------------------------------------------------未完待续--------------------------------------

牛人的理解:http://blog.csdn.net/tuke_tuke/article/details/51588156


















原创粉丝点击