hashmap底层实现原理,职场必问,解决hash冲突

**```
hashmap数组和链表的结合体
1、HashMap 是不是有序的?不是有序的。
2、有没有有序的Map实现类呢?有 TreeMap 和 LinkedHashMap。
3、然后问TreeMap 和 LinkedHashMap 是如何保证它的顺序的? TreeMap 是通过实现 SortMap 接口,能够把它保存的键值对根据 key 排序,基于红黑树,从而保证 TreeMap 中所有键值对处于有序状态。LinkedHashMap 则是通过插入排序(就是你 put 的时候的顺序是什么,取出来的时候就是什么样子)和访问排序(改变排序把访问过的放到底部)让键值有序。
4、你觉得它们两个(Treemap和LinkedHashMap)哪个的有序实现比较好?如果你依然可以回答的话,那么继续问你,你觉得还有没有比它更好或者更高效的实现方式?
为什么要使用HashMap?
HashMap是一个散列桶(数组和链表),它存储的内容是键值对key-value映射
HashMap采用了数组和链表的数据结构,能在查询和修改方面继承了数组的线性查询和链表的寻址修改
HashMap是非synchronized的,线程不安全,所以很快
HashMap可以接受null键和值,而HashTable不行(因为equals()方法需要对象,因为HashMap是后出的api经过处理才可以)
HashMap的工作原理是什么?
然后讲下HashMap中的实现原理,hashmap是由数组和链表组成的。数组是HashMap的本体,而链表则是为了解决hash冲突而存在的,如果定位到数组位置不存在链表(当前Entry的next指向为null),那么对于查找插入等操作很快,仅仅需要一次寻址即可;如果定位到数组有链表,对于添加操作其时间复杂度为O(n),首先遍历链表,存在既覆盖,否则新增。对于查找操作来讲,仍需遍历链表,然后通过key对象的equals方法逐一比对查找。所以,性能考虑,HashMap中的链表出现越少,性能才会越好。
添加元素操作步骤:
以下是具体的 put 过程(JDK1.8)
对 Key 求 Hash 值,然后再计算下标
如果没有碰撞,直接放入桶中(碰撞的意思是计算得到的 Hash 值相同,需要放到同一个 bucket 中)如果碰撞了,以链表的方式链接到后面
如果链表长度超过阀值(TREEIFY THRESHOLD==8),就把链表转成红黑树,链表长度低于6,就把红黑树转回链表
如果节点已经存在就替换旧值
如果桶满了(容量16*加载因子0.75),就需要 resize(扩容2倍后重排)
减少hash冲突?扰动函数可以减少碰撞

  • 原理是如果两个不相等的对象返回不同的 hashcode 的话,那么碰撞的机率就会小些。这就意味着存链表结构减小,这样取值的话就不会频繁调用
    equal 方法,从而提高 HashMap 的性能(扰动即 Hash 方法内部的算法实现,目的是让不同对象返回不同hashcode)。

  • 使用不可变的、声明作 final 对象,并且采用合适的 equals() 和 hashCode()
    方法,将会减少碰撞的发生不可变性使得能够缓存不同键的 hashcode,这将提高整个获取对象的速度,使用 String、Integer
    这样的 wrapper 类作为键是非常好的选择。 为什么 String、Integer 这样的 wrapper 类适合作为键?
    因为 String 是 final,而且已经重写了 equals() 和 hashCode() 方法了。不可变性是必要的,因为为了要计算 hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的 hashcode 的话,那么就不能从 HashMap 中找到你想要的对象。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章