笔者希望做一个系列,整理 Android 基础技术,本章是关于HashMap
HaspMap的默认初始长度是16,并且每次扩展长度或者手动初始化时,长度必须是2的次幂。
为什么长度是2的x次幂和每次扩容都是2倍??
1)当一个key被放进到数组时需要明确自己被放在哪个位置。最简单的当然就是对key进行hash之后h%n确定。而如果数组的长度n是2的x幂,h%n这个操作与h&(n-1)是等价的,会更快, &操作比%更有效率。
2)同时在扩容时,每个key需要重新确定自己在数组中的index,这时如果数组每个位置的元素都变了一次,显然开销会比较大。当容量大小 n 为2的x次方时,n -1 的二进制的后几位全是1,在h为随机数的情况下,与n-1进行与操作时,会分布的更均匀: 想一想,如果n -1的二进制数是1110,当尾数为0时,& 操作出来的值尾数永远为0,那么0001,1001,1101等尾数为1的位置就永远不可能被entry占用,就造成了空间浪费。
什么时候进行扩容?
HashMap设计了一个阈值,其值为容量的0.75,当HashMap所用容量超过了阈值后,就会自动扩充其容量为原来的2倍。
HashMap JDK 1.7 和 1.8 的区别?
1.7 是数组 + 链表;1.8 引入了红黑树
什么时候链表转换成红黑树?
当数组大小超过64并且链表的元素个数超过8,链表转换成红黑树
上面说到的红黑树有什么特点?
- 每个节点非红即黑;
- 根节点总是黑色的;
- 每个叶子节点都是黑色的空节点(NULL节点);
- 如果节点是红色的,则它的子节点必须是黑色的(反之不一定);
- 从根节点到叶节点或空子节点的每条路径,必须包含相同数目的黑色节点(即相同的黑色高度
为什么要用红黑树?
为了解决二叉查找树的缺陷,因为二叉查找树在某些情况下会退化成一个线性结构。
为什么不直接使用红黑树?
我们知道红黑树属于(自)平衡二叉树,但是为了保持“平衡”是需要付出代价的,红黑树在插入新数据后可能需要通过左旋,右旋、变色这些操作来保持平衡,这费事啊。你说说我们引入红黑树就是为了查找数据快,如果链表长度很短的话,根本不需要引入红黑树的,你引入之后还要付出代价维持它的平衡。但是链表过长就不一样了。至于为什么选 8 这个值呢?通过概率统计所得,这个值是综合查询成本和新增元素成本得出的最好的一个值。