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两个索引值

不会缩容

posted @ 2023-06-20 11:24  流星<。)#)))≦  阅读(40)  评论(0编辑  收藏  举报