HashMap源码分析(JDK1.8)- 你该知道的都在这里了

       HashMap是Java和Android程序员的基本功, JDK1.8对HashMap进行了优化, 你真正理解它了吗?

考虑如下问题: 

1、哈希基本原理?(答:散列表、hash碰撞、链表、红黑树

2、hashmap查询的时间复杂度, 影响因素和原理? (答:最好O(1),最差O(n), 如果是红黑O(logn)

3、resize如何实现的, 记住已经没有rehash了!!!(答:拉链entry根据高位bit散列到当前位置i和size+i位置)

4、为什么获取下标时用按位与&,而不是取模%? (答:不只是&速度更快哦,  我觉得你能答上来便真正理解hashmap了)

5、什么时机执行resize?

答:hashmap实例里的元素个数大于threshold时执行resize(即桶数量扩容为2倍并散列原来的Entry)。 PS:threshold=桶数量*负载因子

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;   //初始化桶,默认16个元素
    if ((p = tab[i = (n - 1) & hash]) == null)   //如果第i个桶为空,创建Node实例
        tab[i] = newNode(hash, key, value, null);
    else { //哈希碰撞的情况, 即(n-1)&hash相等
        Node<K,V> e; K k;
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;   //key相同,后面会覆盖value
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);  //红黑树添加当前node
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {
                    p.next = newNode(hash, key, value, null);  //链表添加当前元素
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);  //当链表个数大于等于7时,将链表改造为红黑树
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;            //覆盖key相同的value并return, 即不会执行++size
        }
    }
    ++modCount;
    if (++size > threshold)    //key不相同时,每次插入一条数据自增1. 当size大于threshold时resize
        resize();
    afterNodeInsertion(evict);
    return null;
}

6、为什么负载因子默认为0.75f ? 能不能变为0.1、0.9、2、3等等呢?

答:0.75是平衡了时间和空间等因素; 负载因子越小桶的数量越多,读写的时间复杂度越低(极限情况O(1), 哈希碰撞的可能性越小); 负载因子越大桶的数量越少,读写的时间复杂度越高(极限情况O(n), 哈希碰撞可能性越高)。 0.1,0.9,2,3等都是合法值。

7、影响HashMap性能的因素?

1、 负载因子;

2、哈希值;理想情况是均匀的散列到各个桶。 一般HashMap使用String类型作为key,而String类重写了hashCode函数。

   static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

8、HashMap的key需要满足什么条件? 

答:必须重写hashCode和equals方法, 常用的String类实现了这两个方法。

示例代码:

    private static class KeyClass {
        int age;
        String name;

        public boolean equals(Object anyObject) {
            if (anyObject == this) {
                return true;
            }

            if (anyObject instanceof KeyClass) {
                KeyClass obj = (KeyClass) anyObject;
                if (obj.age == this.age
                        && obj.name == this.name) {
                    return true;
                }
            }
            return false;
        }

        public int hashCode() {
            return name==null? age : age|name.hashCode();
        }
    }

    public static void main(String[] args) {
        HashMap<KeyClass, String> map = new HashMap<>();
        KeyClass obj1 = new KeyClass();
        KeyClass obj2 = new KeyClass();
        obj1.age = 1;
        obj1.name = "Tom";
        obj2.age = 2;
        obj2.name ="Jack";
        map.put(obj1, "
  • 14
    点赞
  • 56
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值