HashMap实现原理
在jdk1.6和jdk1.7中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的键值对会被放在同一位桶里,当桶中元素较多时,通过key值查找的效率较低。而jdk1.8中,HashMap采用位桶+链表+红黑树实现,当链表长度超过阈值(8)时,将链表转化为红黑树,减少查找时间。HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用key的hashCode()方法算出hashcode,然后找到bucket位置来储存值对象. 当获取对象时,通过key的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题(哈希碰撞:通过不同的属性值,算出同一个整数),当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象.
当两个不同的键对象的hashcode相同时会发生什么?
它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。
如果HashMap的大小超过了负载因子(load factor)定义的容量,怎么办?
HashMap默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。
HashSet和HashMap的区别
补充红黑树
HashMap在jdk1.8之后引入了红黑树的概念,表示若桶中链表元素超过8时,会自动转化成红黑树;若桶中元素小于等于6时,树结构还原成链表形式。
引入红黑树原因:红黑树的平均查找长度是log(n),长度为8,平均查找长度为log(8)=3,链表的平均查找长度为n/2,当长度为8时,平均查找长度为8/2=4,这才有转换成树的必要;链表长度如果是小于等于6,6/2=3,虽 然速度也很快的,但是转化为树结构和生成树的时间并不会太短。
选择6和8的原因是:中间有个差值7可以防止链表和树之间频繁的转换。假设一下,如果设计成链表个数超过8则链表转换成树结构,链表个数小于8则树结构转换成链表,如果一个HashMap不停的插入、删除元素,链表个数在8左右徘徊,就会频繁的发生树转链表、链表转树,效率会很低。