20230314 java.util.ArrayDeque
源码学习
构造方法
ArrayDeque 有三个构造方法
- ArrayDeque() :默认底层数组大小是16
- ArrayDeque(int numElements) :不是指定底层数组大小,而是指最少要容纳的元素数量,具体大小是大于这个数量的2的n次幂
- ArrayDeque(Collection<? extends E> c) :底层数组具体大小是不小于集合元素数量的2的n次幂
calculateSize
calculateSize 方法用于计算大于元素数量的2的n次幂
底层数组的大小始终是2的n次幂,这样做是为了方便进行位运算
private static int calculateSize(int numElements) {
int initialCapacity = MIN_INITIAL_CAPACITY;
if (numElements >= initialCapacity) {
initialCapacity = numElements;
initialCapacity |= (initialCapacity >>> 1);
initialCapacity |= (initialCapacity >>> 2);
initialCapacity |= (initialCapacity >>> 4);
initialCapacity |= (initialCapacity >>> 8);
initialCapacity |= (initialCapacity >>> 16);
initialCapacity++;
if (initialCapacity < 0) // Too many elements, must back off
initialCapacity >>>= 1;// Good luck allocating 2 ^ 30 elements
}
return initialCapacity;
}
这里的位运算非常有趣,int是4个字节,也就是32位,>>>表示无符号右移
- 第一次右移1位,并和自身进行或位运算,就能保证前2位如果存在1,1会在最终结果中相同位上
- 第二次在第一次计算的基础上右移2位,并和自身进行或位运算,就能保证前4位如果存在1,1会在结果中
- ...
- 第五次将1扩大到32位,也就是int的位长度
一系列的位运算结束后,结果必定是000111(前面n个0,后面32-n个1),1从哪一位开始取决于入参int的最高位1在哪一位
位运算结束后,结果+1,就能得到大于且最接近入参int的2的n次幂
如果入参是Integer.MAX_VALUE
(\(2^{31}-1\)) ,+1后,会越界成为 Integer.MIN_VALUE
(\(-2^{31}\)),然后判断小于0,再无符号右移一位,也就是\(2^{30}\)
因此,底层数组的大小值域是2的n次幂,且n在区间[4, 30]
二进制表示,负数可以表示的比整数多一个
添加方法 add、push
ArrayDeque中的方法名称中带有First和Last并不是指0和15,而是head和last两个索引,因为使用的是位运算,所以实际这两个索引值可以看作环形索引
- add方法从head向后添加,使用tail从0增加到15
- push方法从last向前添加,使用head从15减小到0
- pop方法和remove方法相同,都是从head向后删除
遍历、迭代器
从head向后环形遍历到tail
扩容、缩容
doubleCapacity 方法进行扩容,将容量扩大到2倍
从head到tail复制到新数组的从0开始的空间
可以看出来,底层数组的索引并不重要,一直操作的都是head和tail两个索引值
不会缩容