哈希表如何存储元素
- 哈希表由数组+链表/红黑树组成,哈希表初始桶数量是16(即数组长度),散列因子(加载因子)是0.75(可自己设置),当桶的使用量达到75%,则对桶进行扩容2倍(就是数组扩容2倍),此时就是对32取余.
- 首先通过hashCode方法获取元素哈希值(int值),然后对16取余,余数作为数组索引,然后将元素存储对应位置中。
- 当出现哈希冲突(即哈希值取余结果相同),java采用链表和红黑树处理这个问题
- 当哈希桶中数据>8,则链表转换为红黑二叉树。
- 当哈希桶中数据减少到6,则红黑二叉树转换为链表。
- 若现在哈希桶中已知数据是7个,当减少数据后,不一定发生红黑树转换为链表,因为哈希桶可能本身就是链表。
影响HashMap性能的参数
- 影响HashMap性能的参数:初始容量、负载(散列)因子。
- 若初始容量给的小,但存储的数据很多,哈希表就会频繁的散列,即重建内部数据结构即重新建立2倍大小哈希表,将原数据再一一存进去,这样导致最后存储数据次数是原来多倍,造成性能浪费。
- 加载因子若给的小,则占用大量内存空间但效率高,若过大则越节省空间但查询效率过低。
哈希值错乱问题
- 当一个对象作为哈希表的键存储时,这个对象就不要进行修改,不然重新计算的哈希值与原来哈希值会不一样,就找不到原数据,造成内存泄漏。
- 只要是以哈希表存储元素,被计算哈希值的字段内容就不要修改,若一定要修改,这个字段就不要放在键的位置,当然这是对map来说,若是对set来说只能存单列,是一定不能修改的。
- 比如当一个对象被存进 HashSet 集合后,就不能修改这个对象中的那些参与计算的哈希值的字段了,否则,对象被修改后的哈 希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为 的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中删除当前对象,从而 造成内存泄露。