前言
  Java里有一个叫做Stack的类,却没有叫做Queue的类(它是个接口名字)。当需要使用栈时,Java已不推荐使用Stack,而是推荐使用更高效的ArrayDeque;既然Queue只是一个接口,当需要使用队列时也ArrayDeque了(次选是LinkedList)。
  总体介绍
  要讲栈和队列,首先要讲Deque接口。Deque的含义是“double ended queue”,即双端队列,它既可以当作栈使用,也可以当作队列使用。下表列出了Deque与Queue相对应的接口:

  下表列出了Deque与Stack对应的接口:

  上面两个表共定义了Deque的12个接口。添加,删除,取值都有两套接口,它们功能相同,区别是对失败情况的处理不同。一套接口遇到失败会抛出异常,另一套遇到失败会返回特殊值(false或null)。除非某种实现对容量有限制,大多数情况下,添加操作是不会失败的。虽然Deque的接口有12个之多,但无非是对容器的两端进行操作,或添加,或删除,或查看。明白了这一点讲解起来会非常简单。
  ArrayDeque和LinkedList是Deque的两个通用实现,由于官方更推荐使用AarryDeque用作栈和队列,加之上一篇已经讲解过LinkedList,本文将着重讲解ArrayDeque的具体实现。
  从名字可以看出ArrayDeque底层通过数组实现,为了满足可以同时在数组两端插入或删除元素的需求,该数组还必须是循环的,即循环数组(circular array),也是说数组的任何一点都可能被看作起点或者终点。ArrayDeque是非线程安全的(not thread-safe),当多个线程同时使用的时候,需要程序员手动同步;另外,该容器不允许放入null元素。

  上图中我们看到,head指向首端第一个有效元素,tail指向尾端第一个可以插入元素的空位。因为是循环数组,所以head不一定总等于0,tail也不一定总是比head大。
  方法剖析
  addFirst()

  addFirst(E e)的作用是在Deque的首端插入元素,也是在head的前面插入元素,在空间足够且下标没有越界的情况下,只需要将elements[--head] = e即可。

  实际需要考虑:1.空间是否够用,以及2.下标是否越界的问题。上图中,如果head为0之后接着调用addFirst(),虽然空余空间还够用,但head为-1,下标越界了。下列代码很好的解决了这两个问题。
  //addFirst(E e)
  public void addFirst(E e) {
  if (e == null)//不允许放入null
  throw new NullPointerException();
  elements[head = (head - 1) & (elements.length - 1)] = e;//2.下标是否越界
  if (head == tail)//1.空间是否够用
  doubleCapacity();//扩容
  }
  上述代码我们看到,空间问题是在插入之后解决的,因为tail总是指向下一个可插入的空位,也意味着elements数组至少有一个空位,所以插入元素的时候不用考虑空间问题。