ArrayDeque不是线程安全的。
ArrayDeque不可以存取null元素,因为系统根据某个位置是否为null来判断元素的存在。
当作为栈使用时,性能比Stack好;当作为队列使用时,性能比LinkedList好。
一、常用方法
1.添加元素 addFirst(E e)在数组前面添加元素 addLast(E e)在数组后面添加元素 offerFirst(E e) 在数组前面添加元素,并返回是否添加成功 offerLast(E e) 在数组后天添加元素,并返回是否添加成功 2.删除元素 removeFirst()删除第一个元素,并返回删除元素的值,如果元素为null,将抛出异常 pollFirst()删除第一个元素,并返回删除元素的值,如果元素为null,将返回null removeLast()删除最后一个元素,并返回删除元素的值,如果为null,将抛出异常 pollLast()删除最后一个元素,并返回删除元素的值,如果为null,将返回null removeFirstOccurrence(Object o) 删除第一次出现的指定元素 removeLastOccurrence(Object o) 删除最后一次出现的指定元素 3.获取元素 getFirst() 获取第一个元素,如果没有将抛出异常 getLast() 获取最后一个元素,如果没有将抛出异常 4.队列操作 add(E e) 在队列尾部添加一个元素 offer(E e) 在队列尾部添加一个元素,并返回是否成功 remove() 删除队列中第一个元素,并返回该元素的值,如果元素为null,将抛出异常(其实底层调用的是removeFirst()) poll() 删除队列中第一个元素,并返回该元素的值,如果元素为null,将返回null(其实调用的是pollFirst()) element() 获取第一个元素,如果没有将抛出异常 peek() 获取第一个元素,如果返回null 5.栈操作 push(E e) 栈顶添加一个元素 pop(E e) 移除栈顶元素,如果栈顶没有元素将抛出异常 6.其他 size() 获取队列中元素个数 isEmpty() 判断队列是否为空 iterator() 迭代器,从前向后迭代 descendingIterator() 迭代器,从后向前迭代 contain(Object o) 判断队列中是否存在该元素 toArray() 转成数组 clear() 清空队列 clone() 克隆(复制)一个新的队列
二、源码分析
1. 两个重要的索引:head和tail
2. 构造方法
3. 分配合适大小的数组
4. 扩容
- // 第一个元素的索引
- private transient int head;
- // 下个要添加元素的位置,为末尾元素的索引 + 1
- private transient int tail;
- public ArrayDeque() {
- elements = (E[]) new Object[16]; // 默认的数组长度大小
- }
- public ArrayDeque(int numElements) {
- allocateElements(numElements); // 需要的数组长度大小
- }
- public ArrayDeque(Collection<? extends E> c) {
- allocateElements(c.size()); // 根据集合来分配数组大小
- addAll(c); // 把集合中元素放到数组中
- }
- private void allocateElements(int numElements) {
- int initialCapacity = MIN_INITIAL_CAPACITY;
- // 找到大于需要长度的最小的2的幂整数。
- // 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 = (E[]) new Object[initialCapacity];
- }
- // 扩容为原来的2倍。
- private void doubleCapacity() {
- assert head == tail;
- int p = head;
- int n = elements.length;
- int r = n - p; // number of elements to the right of p
- int newCapacity = n << 1;
- if (newCapacity < 0)
- throw new IllegalStateException("Sorry, deque too big");
- Object[] a = new Object[newCapacity];
- // 既然是head和tail已经重合了,说明tail是在head的左边。
- System.arraycopy(elements, p, a, 0, r); // 拷贝原数组从head位置到结束的数据
- System.arraycopy(elements, 0, a, r, p); // 拷贝原数组从开始到head的数据
- elements = (E[])a;
- head = 0; // 重置head和tail为数据的开始和结束索引
- tail = n;
- }
- // 拷贝该数组的所有元素到目标数组
- private <T> T[] copyElements(T[] a) {
- if (head < tail) { // 开始索引大于结束索引,一次拷贝
- System.arraycopy(elements, head, a, 0, size());
- } else if (head > tail) { // 开始索引在结束索引的右边,分两段拷贝
- &nb

本文详细介绍了ArrayDeque类的主要功能和使用方法,包括添加、删除、获取元素等操作,并深入解析其内部实现原理,如扩容机制、索引管理和并发控制等。

最低0.47元/天 解锁文章
2328





