美文网首页
ArrayDeque源码分析

ArrayDeque源码分析

作者: gcno93 | 来源:发表于2021-09-24 02:12 被阅读0次

    allocateElements() 初始化容器

      private void allocateElements(int numElements) {
            int initialCapacity = MIN_INITIAL_CAPACITY;
            // Find the best power of two to hold elements.
            // Tests "<=" because arrays aren't kept full.
            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
            }
            elements = new Object[initialCapacity];
        }
    

    上面的代码,我看了几个鈡,终于有点理解了,也不知对,还是错,这段代码主要是获取initialCapacity 最近的2的幂次方,下面是我分析的结果,有点长,我也不知怎么简化

                initialCapacity |= (initialCapacity >>>  1);
                initialCapacity |= (initialCapacity >>>  2);
                initialCapacity |= (initialCapacity >>>  4);
                initialCapacity |= (initialCapacity >>>  8);
                initialCapacity |= (initialCapacity >>> 16);
    
               假设我的initialCapacity  =  32
              
               我们先来看第一个      initialCapacity |= (initialCapacity >>>  1);
    
               32的二进制是:00000000000000000000000000100000
               initialCapacity >>>  1 也就是无符号右移1位,也就是等于16,
               16的二进制:00000000000000000000000000010000
               initialCapacity = initialCapacity  | (initialCapacity >>>  1) 也就是 32 | 16
                00000000000000000000000000100000   =====》32
                                            或(|)
                00000000000000000000000000010000   =====》16
                00000000000000000000000000110000   =====》48
              
                仔细观察,你会发现最后的结果110000(48)  比 原来的数据100000(32)第二位的0变成了1
    
                我们继续   initialCapacity |= (initialCapacity >>>  2);
                
                 这时 initialCapacity = 48 
                 48的二进制: 00000000000000000000000000110000
                 initialCapacity >>>  2  也就是 48 无符号右移2位 也就是等于12
                 12的二进制:00000000000000000000000000111100
    
                 00000000000000000000000000110000 =====》48
                                               或(|)
                 00000000000000000000000000001100 =====》12
                 00000000000000000000000000111100 =====》60
    
                  仔细观察,你会发现最后的结果111100(60)  比 原来的数据100000(110000)第三位,第四位的0都变成了1
    
                 我们继续   initialCapacity |= (initialCapacity >>>  4);
                
                 这时 initialCapacity = 60
                 initialCapacity >>>  4  也就是 60无符号右移2位 也就是等于3 
                 12的二进制:00000000000000000000000000000011
    
                 00000000000000000000000000111100 =====》48
                                               或(|)
                 00000000000000000000000000000011 =====》3
                 00000000000000000000000000111111 =====》63
    
                 仔细观察,你会发现最后的结果111111(63)  比 原来的数据111100(110000)第五位,第六位的0都变成了1
                
                经过这三步,我发现,这代码就是为了把100000(32)的不是1的位弄成1的位
    
                那这是为什么呢?
    
                你看看 1, 4 ,8 ,16,32,64的二进制就完事了
                64 = 1000000
                比喻上面的63 (111111) + (000001) =  1000000
                
                所以上面的代码是为了找出 2的幂次方-1的数,也就是说32的最近2的幂次方不就是64吗????
    
                至于  为啥是  >>> 1   >>>2    >>>4  >>>8  >>>16 ?
    
                >>> 1  : 这个时候110000(48)  比 原来的数据100000(32)第二位的0变成了1,那我们就可以确定2位,第1位,第二位肯定是1了,下面我直接>>>2 就好
                >>> 2   这个时候111100(60)  比 原来的数据100000(110000)第三位,第四位的0都变成了1,那我们可以确定第1,2,3,4,肯定是1了,所以下面我直接>>>4就好
                 >>>4 这个时候 111111(63)  比 原来的数据111100(110000)第五位,第六位的0都变成了1,那我们可以确定 第1,2,3,4,5,6,都是1了,尽管下面>>>8,>>>16,最后的结果还是111111(63),因为
                      00000000000000000000000000111111 =====》63  >>>8  右移8位
                                              或(|)
                      00000000000000000000000000000000 =====》0
    
                      00000000000000000000000000111111 =====》63  结果还是不变的
              
              
                
    

    doubleCapacity() 扩容

    private void doubleCapacity() {
            assert head == tail;//head == tail是否相等
            int p = head; //头部下标
            int n = elements.length; //旧数组长度
            int r = n - p; // 右边的元素
            int newCapacity = n << 1;//原来的*2
            if (newCapacity < 0) 
                throw new IllegalStateException("Sorry, deque too big");
            Object[] a = new Object[newCapacity];//创建一个新的容器数组
            System.arraycopy(elements, p, a, 0, r); //拷贝旧数组的右边数组到新数组的左边
            System.arraycopy(elements, 0, a, r, p);//拷贝旧数组的左边数组到新数组的右边
            elements = a;//elements = 新的数组
            head = 0;//最开始0
            tail = n;//旧数组长度
        }
    

    addFirst(E e) 首端插入元素,也就是在head的前面插入元素

      public void addFirst(E e) {
            if (e == null) //可见不能插入空值
                throw new NullPointerException();
            //第一次的时候 head =0 0-1=-1 但是-1的二进制是所有位都是1
            //(head - 1) & (elements.length - 1) 也即是 elements.length - 1
          //保证了head一定在0到elements.length- 1之间
            elements[head = (head - 1) & (elements.length - 1)] = e;
            if (head == tail)
                doubleCapacity();
        }
    

    addLast(E e) 在Deque的尾端插入元素,也就是在tail的位置插入元素,由于tail总是指向下一个可以插入的空位

      public void addLast(E e) {
            if (e == null) //可见不能插入空值
                throw new NullPointerException();
            elements[tail] = e; //应为tail总是指向下一个可插入的位置,所以可以直接赋值
            //elements.length的长度一定是2的幂次方,所以elements.length - 1的二进制肯定是1111111
            //当(tail + 1) & (elements.length - 1) 肯定是(tail + 1)
            if ( (tail = (tail + 1) & (elements.length - 1)) == head) 
                doubleCapacity(); //扩容,上面已经分析了
        }
    

    pollFirst() 删除并返回Deque首端元素,也即是head位置处的元素

        public E pollFirst() {
            int h = head; //头部下标
            @SuppressWarnings("unchecked")
            E result = (E) elements[h]; //获取头部值
            // Element is null if deque empty
            if (result == null) //不等null 返回
                return null;
            elements[h] = null;     // Must null out slot//头部元素删除
            head = (h + 1) & (elements.length - 1);//h 需要加1
            return result;//返回
        }
    

    pollLast() 作用是删除并返回Deque尾端元素,也即是tail位置前面的那个元素

    public E pollLast() {
            int t = (tail - 1) & (elements.length - 1); //最后一个
            @SuppressWarnings("unchecked")
            E result = (E) elements[t];//获取最后一个值
            if (result == null) //null 返回null
                return null;
            elements[t] = null; //最后一个值删除
            tail = t; //设置tail 下标,因为t 位置已经null 是下一个可以插入的位置,所以  tail = t;
            return result;
        }
    

    peekFirst() 返回但不删除Deque首端元素,也即是head位置处的元素

     public E peekFirst() {
            // elements[head] is null if deque empty
            return (E) elements[head]; //直接返回
        }
    

    peekLast() 返回但不删除Deque尾端元素,也即是tail位置前面的那个元素

      public E peekLast() {
            return (E) elements[(tail - 1) & (elements.length - 1)] ;//tail - 1的元素
        }
    

    相关文章

      网友评论

          本文标题:ArrayDeque源码分析

          本文链接:https://www.haomeiwen.com/subject/cdtogltx.html