hashmap的性能问题本质就是数组,链表,红黑树的问题
贴一篇CSDN的文章 对hashmap的结构讲的很简单易懂
https://blog.csdn.net/Jae_Peng/article/details/79562432
为什么要用hashmap呢(hashmap的优点)
假设分布足够均匀,没有发生hash碰撞,那就是一个Node数组(Node实现了map.Entry接口 实际就是键值对数组 默认初始长度16 空位置为null)
所以查询数据的时间复杂度位O(1);
而插入数据的时候通过hash算法计算插入位置,然后替换数组中null位,
(hash算法时间复杂度O(1));
综上 插入查询都为O(1), 保留了数组的优点;
但如果发生了hash碰撞(hashcode相同)呢?
重复位会调用equals方法(时间复杂度O(n)),比较key是否一样,如果不一样,则放入单链表中,而此时hashmap查询的最坏时间复杂度也变为O(n)
当同一个位置发生的哈希碰撞越来越多,链表长度就越来越长,在jdk1.8之后,链表长度如果>=8,就会转变成红黑树,优化插入查询操作(RB TREE 一种平衡查询二叉树 通过二分查找 查询的时间复杂度均为O(logn) 而红黑树通过左旋右旋变色等操作 可以做到自我平衡 能保证时间复杂度不变);
hashmap的缺点:
hashmap的resize()操作会对hashmap进行扩容操作,扩容长度为原来的两倍,而resize会对所有原来的元素重新计算hash值,很浪费性能,如果在多线程环境下,还会出现死锁的问题.
决定是否扩容取决于负载因子和元素数量之积是否大于数组长度,默认负载因子为0.75,要避免频繁扩容 在new hashmap时就能更具情况给定适合的长度,或者增大负载因子的值,但负载因子的值越大,同样数组长度中就有更多的元素,更容易发生哈希碰撞,插入和查询的性能就会下降.
红黑树左旋 右旋 变色
每次插入数据 红黑树会根据hashcode大小放在左右2边,如果破坏了红黑树的5条规则,红黑树就会自平衡,不管怎么变,都遵循的2条原则:
根节点是中值 树的中序遍历顺序不变
红黑树的5条原则也是为了保证二分查找的性能