面试题答案
一键面试哈希冲突处理机制
- 原理:HashMap使用链地址法(拉链法)处理哈希冲突。当两个或多个键的哈希值相同时,它们会被存储在同一个桶(bucket)中,形成一个链表。
- 示例:假设哈希函数为
hash(key) = key % capacity
,当两个不同的键key1
和key2
满足key1 % capacity == key2 % capacity
时,就会发生哈希冲突,它们对应的键值对会被放在同一个链表中。
扩容机制
- 触发条件:当HashMap中的元素数量(size)达到负载因子(loadFactor)与当前容量(capacity)的乘积时,就会触发扩容。默认负载因子为0.75。例如,当容量为16,负载因子为0.75时,当元素数量达到12(16 * 0.75)时,就会触发扩容。
- 扩容过程:扩容时,新的容量为原来容量的2倍。然后会重新计算每个键值对在新容量下的哈希值和存储位置,将原链表中的元素重新分配到新的桶中。这个过程被称为rehash。
红黑树转换机制
- 转换条件:当链表长度大于等于8且当前HashMap的容量大于等于64时,链表会转换为红黑树。这是因为在大数据量下,链表的查找时间复杂度为O(n),而红黑树的查找时间复杂度为O(log n),可以提高查找效率。
- 转回条件:当红黑树节点数量小于等于6时,红黑树会转回链表。这是因为在节点数量较少时,链表的插入和删除操作效率更高。
调优建议
- 预估算容量:在实际项目中,如果能够预先估算数据量,可以设置合适的初始容量,避免频繁扩容。例如,已知会有1000个元素,可以将初始容量设置为大于1000 / 0.75的2的幂次方值,如1664(1024 * 2)。
- 调整负载因子:对于读操作频繁的场景,可以适当降低负载因子,减少哈希冲突,提高查找效率,但会占用更多内存。对于写操作频繁的场景,可以适当提高负载因子,减少扩容次数,但可能会增加哈希冲突。
- 定制哈希函数:根据业务数据特点定制哈希函数,使哈希值分布更均匀,减少哈希冲突。例如,对于字符串类型的键,可以使用更复杂的哈希算法,如DJB2算法。
- 避免不必要的对象创建:在向HashMap中添加元素时,尽量复用已有的对象,避免频繁创建新对象,减少垃圾回收压力。