基础也是重点

HashMap 是典型的key 对应 value的接口  里面是数组加链表key 的hash值冲突时 用链地址法解决冲突,在同一个相同下标的table中用链表的形式连接起来

 

在这里就可以产生问题:

  1. keyhash值是怎么来的?
  2. 这样的hash方式有什么好处?

 

:  在jdk1.7 中

static int indexFor(int h, int length) {    

     return h & (length-1);    

 }  

 

要明确的是目的是为了使table里的数据分布的更均匀

与运算是转化为二进制数 再相与( 都为1 则输出1 见0为0)

比如 128& 129

128 二进制:10000000

129 二进制:10000001

结果为

10000000   128

可以看出与偶数相与时,一定会是偶数

 

HashMap的初始大小和扩容都是以2的次方来进行的,换句话说length-1换成二进制永远是全部为1,比如容量为16,则length-1为1111,所以相与的数可能是偶数或者奇数,这样hash后的值在table中尽量的分散,前面就有提到hash的目的就是为了使分布更均匀 减少冲突

 

而在jdk1.8中

static final int hash(Object key) {

        int h;

        return (key == null) ? 0 : (h =key.hashCode()) ^ (h >>> 16);

    }

因为对自己改造过的哈希大量冲突时的红黑树有信心,所以简单一点,只是把高16异或下来(异或的操作是相同为0 不同为1) 


Java7扩容时,遍历每个节点,并重新hash获得当前数组的位置并添加到链表中;Java8进一步做了优化, 将元素的hash和旧数组的大小(大小为2次幂)做与运算,为0则表示数组位置不变,不为0则表示需要移位,新位置为原先位置+旧数组的小大(新数组大小为旧数组翻倍),并将当前链表拆分为两个链表,一个链表放到原先位置,一个链路放到新位置,效率比Java7高。
额外提一点,Java的链表节点数超过8个时,会将链表转化为红黑树,当hash命中很低时,效率比Java7高很多,有兴趣可以看看源码,写的很好。


学习了多年的java的人对hashCode和equals方法都不是很清楚。 
总的来说, Java中的集合(Collection)有两类,一类是List,另一类是Set。 前者集合内的元素是有序的,元素可以重复; 后者元素无序,但元素不可重复 。那么这里就有一个比较严重的问题了:如何判断两个对象相等呢? 这就是Object.equals方法了。 但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。 
也就是说,每次添加对象都需要与集合中的已有对象进行一次比较。这显然会大大降低效率。     
于是, Java采用了哈希表的原理。 哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。可以这样理解, hashCode方法实际上返回的就是对象存储的物理地址 (实际可能并不是)。    
这样一来, 当集合要添加新的元素时,先调用这个元素的hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;[color=red]如果这个位置上已经有元素了,就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。 所以这里存在一个冲突解决的问题。[/color] 
这样一来实际调用equals方法的次数就大大降低了,几乎只需要一两次。     所以,Java对于eqauls方法和hashCode方法是这样规定的: 
1、如果两个对象相同,那么它们的hashCode值一定要相同;  
2、如果两个对象的hashCode相同,它们并不一定相同 ; 
上面说的对象相同指的是用eqauls方法比较。 
所以像String,Math,Integer等一些类重写了equals方法后都会同样的重写hashCode方法。 
为什么要重写equals呢,因为这些类想要比较的是内容而不是对象的存储地址 (存在疑问)  




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值