hashCode

hashCode方法

HashSet和HashMap 使用后台数组(backing array)作为桶,并使用链表(linked list)存储键/值对。

桶的后台数组:如下所示

 

hashCode() 返回 1, 45等

 

1)使用键(key)和值(value)将一个对象放入 map 中时,会隐式调用 hashCode() 方法,返回哈希值(hash code value),比如 123。两个不同的键能够返回一样的哈希值。良好的哈希算法(hashing algorithm)能够将数值分散开。在上面的例子中,我们假设 (“John”,01/01/1956) 的键和 (“Peter”, 01/01/1995) 的键返回相同的哈希值,都是 123

 

Java equals vs hashCode

 

2)当返回一个 hashCode,例如是 123,初始的 HashMap 容量为 10,它如何知道存储到后台数组(backing array)的哪个索引(index)呢?HashMap 内部会调用 hash(int ) 和 indexFor(int h, int length) 方法。这被称为哈希函数(hashing function)。
简要解释下这个函数:

hashCode() % capacity

123%10=3

456%10=6

这表示,“hashCode = 123”存储在备份数组的索引3上。
容量为 10 的情况下,你可能得到的数字在 09 之间。
一旦 HashMap 达到容量的 75%,也就是哈希因子(hash factor)默认值 0.75,后台数组(backing array)的容量就会加倍,发生重散列(rehashing)为新的 20 的容量重新分配桶。


hashCode() % capacity

123%20=3

456%20=16

如上图所示,键/值对以链表形式存储。两个不同的键可以产生一样的 hashCode,例如123,并存储在同一个 bucket 中,理解这点至关重要。例如,上面例子中的 “John, 01/01/1956” 和 “Peter, 01/01/1995“ 。你如何只检索 “John, 01/01/1956” 呢?此时你的 key 所属类的 equals() 方法会被调用。它遍历 bucket 为 “123” 的 LinkedList 中的每个条目,使用 equals() 方法找到并检索出键为 “John, 01/01/1956” 的条目。这就是在你的类中实现 hashCode() 和 equals() 方法重要性的原因。如果你使用一个现有的包装类,如 Integer 或 String 作为键,它们已经实现了这两个方法。如果你使用自己写的类作为键,如 “John, 01/01/1956” 这样含有名字和出生日期属性的“MyKey”,你有责任正确地实现这些方法。

不同的对象调用 hashCode() 方法应该返回不同的值。如果不同的对象返回相同的值,会导致更多的键/值对存储在同一个 bucket 中。这会降低 HashMap 和 HashSet 的性能。

总结:hashmap是由虚拟机内部维护的一张hash表控制的, key通过hashcode方法计算出一个数,每一个hash值对应表中的一个桶。hashmap是不允许key重复的,因为get时需要根据key值寻找v,put key时要遍历表里相同hash的所有key,判断是否有key和它equals相等,如果不相等才能插入,否则无法插入。那么如果key是一个类呢?所有类都继承与object,在obj里默认实现了equals和hashcode方法,eq默认是判断地址,而hashcode也有一套算法。如果我们不重写这两个方法,那么自然hash不同可以插入,但是如果我们重写了hashcode方法使hashcode相同,由于没有重写eq方法,所以调用默认的eq也就是判断地址,所以eq不同可以插入,所以重写hashcode并没有起作用。那么如果单独重写它的eq,而hash不同,则也可以插入,也就说明了hashmap判断重复是通过key的hashcode值。那么只好同时重写hash和eq方法,使hash值相同,那么遍无法插入map中了。再说说hashset,和hashmap类似,也是根据hash值判断重复,与hashmap不相同的是,hashmap判断的是key的hashcode,hashset判断的是元素的hashcode。

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值