ArrayDeque使用及源码分析

类介绍

          ArrayDeque类是Deque接口的一个可变大小的数组实现,我们通常称之为双端队列。该类具有以下一些特点:

  1. 该队列没有容量限制,可以根据使用需要自动增长;
  2. 该队列不是线程安全的;
  3. 不允许存储null;
  4. 该队列作为一个栈来使用比stack快,作为一个队列使用比linkedList快。
  5. 该双端队列的iterator方法返回的迭代器

基本使用

public class ArrayDequeTest {
    public static void main(String[] args) {
        Deque<String> queue = new ArrayDeque<>();

        //添加元素
        queue.addFirst("first element");
        queue.addLast("last element");
        queue.offerFirst("offerfirst element"); //成功返回true
        queue.offerLast("offerlast element"); //成功返回true
        queue.addFirst("first element");
        queue.addFirst("first element");
        queue.addFirst("first element");
//        int index=0,size=queue.size();
//        while (index++<size){
//            System.out.println(queue.removeFirst());
//        }

        //删除元素
        System.out.println(queue.pollFirst());
        System.out.println(queue.pollLast());
        System.out.println(queue.removeFirst());
        System.out.println(queue.removeLast());
        System.out.println(queue.removeFirstOccurrence("first element"));
        System.out.println(queue.removeLastOccurrence("first element"));
        /**输出:
        * first element
        * offerlast element
        * first element
        * last element
        * true
        * true
        * */
        //仅仅获取元素,若无元素,会抛出异常
        System.out.println(queue.getFirst());
        System.out.println(queue.getFirst());
        System.out.println(queue.getLast());
        System.out.println(queue.peekFirst());
        System.out.println(queue.peekLast());
        /**
        * offerfirst element
        * offerfirst element
        * offerfirst element
        * */
        //队列操作
        queue.clear();
        System.out.println(queue.size());
        queue.add("add element");
        System.out.println(queue.offer("offer element"));
        System.out.println(queue.element()); //若队列为空,则抛出异常
        System.out.println(queue.remove()); //若队列为空,则抛出异常
        System.out.println(queue.poll()); //若队列为空,则返回nul
        System.out.println(queue.peek()); //若队列为空,则返回null
        /**
        * 0
        * true
        * add element
        * add element
        * offer element
        * null
        * */


        //栈操作
        queue.push("push element");
        System.out.println(queue.pop()); //若栈为空,则抛出异常
        //输出: push element


//        queue.addFirst(null);  //输出:Exception in thread "main" java.lang.NullPointerException
//        queue.addLast(null); //输出:Exception in thread "main" java.lang.NullPointerException
    }
}

关键源码分析

allocateElements方法

该方法在类构造函数会使用到,其作用是根据给定的入参numElements,生成刚好比numElements大的2的n次幂数。其中在

initialCapacity++之前,initialCapacity被转换成了一个有效数字全部为1的二进制数,然后给initialCapacity加1,恰好就得到了一个2的n次幂数值。用该数值作为双端队列elements数组的初始值,在后续的操作中非常有用。

    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];
    }

addFirst方法

public void addFirst(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[head = (head - 1) & (elements.length - 1)] = e;
    if (head == tail)
        doubleCapacity();
}

通过allocateElements方法,我们可以保证任何时刻elements.length都可以表示为2^n(n为正整数),因此,element.length-1的二进制表示为低n为全部为1,高位全部为0的数。

对于result =(head-1)& (elements.length - 1):

如果0 <= head-1 < element.length,那么result=head-1。

如果head-1 = -1,那么将-1的补码与elements.length - -1 相与的结果是elements.lenght。

综上所述,head-1不可能小于-1,大于或者等于elements.length。并且,head是循环的。

如果,程序想要向ArrayDeque中添加一个null值,程序会抛出一个空指针异常。

addLast方法

public void addLast(E e) {
    if (e == null)
        throw new NullPointerException();
    elements[tail] = e;
    if ( (tail = (tail + 1) & (elements.length - 1)) == head)
        doubleCapacity();
}

同addFirst方法,由于elements.lenth-1的特殊性, (tail + 1) & (elements.length - 1))永远在0-elements.length - 1之间循环,不会发生越界。

总结

ArrayDeque是在jdk1.6之后出现的,可以作为栈使用,也可以作为队列使用。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值