HashMap中entry.hash == hash && (k == key || key.equals(k))


在看HashMap源码时看到get(key)方法时,对一判断条件开始时不太理解:

public V get(Object key) {  
        if (key == null)  
            return getForNullKey();  
        int hash = hash(key.hashCode());  
        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.equals(k)))  
                return e.value;  
        }  

        return null;  
    }  

e.hash == hash && ((k = e.key) == key || key.equals(k))
在HashMap中寻找key对应的映射关系时,如果上述判断条件成立,则代表map中存在对应映射关系。接下来逐步分析该判断条件。

e.hash == hash

刚开始这一步不太理解,我以为凡是在同一个桶中的节点,对应hash应该全相同啊,为何还要加上这一步,是不是多余啊。考虑了一会,觉得肯定是自己的问题,但还是不解。因此就回到源码中,认真分析,终于分析清楚。
首先,在HashMap中,会对key的hashCode值进行二次hash计算,得到最终hash值。因此,如果key相同的话,对应的hashCode值肯定相同,那么计算得到的hash值也肯定相同,然后通过IndexFor()方法会求得索引位置也相同,即相同key在哈希表中的实际存储位置也相同(在同一个桶中)。但是,存在一个问题,在同一个桶中的节点(桶中可能存在0个或1个或多个节点),其key对应的hash值不一定相同!!这就是我刚开始困惑的地方,因为我默认认为key相同则hash相同,则在同一个桶中的节点key也相同!这是错误的!!indexFor()是通过hash & (length - 1)计算得到的索引位置,因此,不同的hash值可能会映射到同一个桶中!所以这就是e.hash == hash存在的依据!!如果缺少这个判断条件,仅通过(k = e.key) == key || key.equals(k)其实也可以进行判断,但是equals方法相当耗时!如果两个key的hash值不同,那么这两个key肯定不相同,进行equals比较是扯淡的!
所以先通过e.hash == hash该条件,将桶中很多不符合的节点pass掉。然后对剩下的节点继续判断。

(k = e.key) == key || key.equals(k)

这个判断条件就会牵扯出经典的经验:重写equals方法时一定要重写hashCode方法!
因为默认对象的hashCode值一般是内存地址对应的数字,所以不同的对象其hashCode值一般不同。
当我们在重写equals方法时,如果两个对象逻辑上相同即可。但是如果不重写hashCode的话,就会在HashMap中出现问题,两个对象明明逻辑上相同,但是因为默认hashCode值不同,就会认为两个对象不同。所以当用HashMap存储对象的时候,一定要重写hashCode()方法!
hashCode()方法重写规则:当equlas方法返回true时,两个对象的hashCode必须一样!

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值