java源码解读--queue

queue接口特点:可以模拟队列行为,即“先进先出”。

接口结构

queue接口继承了Collection接口,并增加了一些新方法

12345678910111213141516
public interface <E> extends Collection<E>{

    boolean add(E e);	//将元素插入队列,如果失败返回false    boolean offer(E e);	//移除并返回队列中的第一个元素,队列为空时,抛异常    E remove();	//移除并返回队列中的第一个元素,队列为空时,返回null    E poll();	//返回队列中第一个元素,但不移除,队列为空时,抛异常    E element();	//返回队列中第一个元素,但不移除,对列为空时,返回null    E peek();

}

抽象类AbstractQueue

queue接口中,add与offer、remove与poll、element与peek,功能一致,只是对异常情况的处理不同。AbstractQueue源码中可以看出这些方法处理异常的方式。

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849
public abstract class AbstractQueue<E>    extends AbstractCollection<E>    implements <E> {

    protected AbstractQueue() {    }

	//add底层调用offer,当offer失败返回false时,add方法抛出异常    public boolean add(E e) {        if (offer(e))            return true;        else            throw new IllegalStateException("Queue full");    }	//remove底层调用poll,当poll返回null时,remove方法抛出异常     public E remove() {        E x = poll();        if (x != null)            return x;        else            throw new NoSuchElementException();    }	//element底层调用peek,当peek返回null时,element方法抛出异常    public E element() {        E x = peek();        if (x != null)            return x;        else            throw new NoSuchElementException();    }	//clear方法循环调用poll,直到返回为null    public void clear() {        while (poll() != null)            ;    }

    public boolean addAll(Collection<? extends E> c) {        if (c == null)            throw new NullPointerException();        if (c == this)            throw new IllegalArgumentException();        boolean modified = false;        for (E e : c)            if (add(e))                modified = true;        return modified;    }

}

Deque接口

Deque是双端队列,底层由循环数组实现,其继承了Queue接口,并扩展了新特性。
Deque重写了Queue的全部方法,Stack、Collection的部分方法,并增加了对首尾元素处理的相关方法。

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
public interface Deque<E> extends <E> {

    void addFirst(E e);

    void addLast(E e);

    boolean offerFirst(E e);

    boolean offerLast(E e);

    E removeFirst();

    E removeLast();

    E pollFirst();

    E pollLast();

    E getFirst();

    E getLast();

    E peekFirst();

    E peekLast();

    boolean removeFirstOccurrence(Object o);

    boolean removeLastOccurrence(Object o);

    // *** Queue methods ***

    boolean add(E e);

    boolean offer(E e);

    E remove();

    E poll();

    E element();

    E peek();

    // *** Stack methods ***

    void push(E e);

    E pop();

    // *** Collection methods ***

    boolean remove(Object o);

    boolean contains(Object o);

    public int size();

    Iterator<E> iterator();

    Iterator<E> descendingIterator();

}

ArrayDeque

ArrayDeque不可以存取null元素,因为会根据某个位置是否为null来判断元素是否存在。
当作为栈使用时,性能比stack好,作为队列使用时,性能比linkedlist好

类定义

继承了AbstractCollection,实现了Deque接口

12
public class ArrayDeque<E> extends AbstractCollection<E>                           implements Deque<E>, Cloneable, Serializable

重要的成员变量

1234
// 第一个元素的索引  private transient int head;  // 下个要添加元素的位置,为末尾元素的索引 + 1  private transient int tail;

构造方法

1234567891011121314
//默认数组大小16   public ArrayDeque() {       elements = new Object[16];   }//传入数组大小   public ArrayDeque(int numElements) {//调整实际数组大小为大于传入值的最小的2的幂次       allocateElements(numElements);   }//直接传入集合   public ArrayDeque(Collection<? extends E> c) {       allocateElements(c.size());       addAll(c);   }

调整数组大小

1234567891011121314151617
private void allocateElements(int numElements) {      int initialCapacity = MIN_INITIAL_CAPACITY;      // 找到大于需要长度的最小的2的幂整数。      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];  }

add

12345678910111213141516171819202122232425262728293031323334
   public void addFirst(E e) {       if (e == null)           throw new NullPointerException();//因为elements.length是2的幂次,(head - 1) & (elements.length - 1)相当于求模操作//head-1只可能为-1,-1&(elements.length - 1)=(elements.length - 1)       elements[head = (head - 1) & (elements.length - 1)] = e;       if (head == tail)           doubleCapacity();   }

   public void addLast(E e) {       if (e == null)           throw new NullPointerException();       elements[tail] = e;//与head操作类似,为了处理tail=length-1的情况       if ( (tail = (tail + 1) & (elements.length - 1)) == head)           doubleCapacity();   }

   public boolean add(E e) {       addLast(e);       return true;   }

   public boolean offerFirst(E e) {       addFirst(e);       return true;   }

   public boolean offerLast(E e) {       addLast(e);       return true;   }

remove

12345678910111213141516171819202122232425262728293031323334353637383940
   public E removeFirst() {       E x = pollFirst();       if (x == null)           throw new NoSuchElementException();       return x;   }

   public E removeLast() {       E x = pollLast();       if (x == null)           throw new NoSuchElementException();       return x;   }

   public E pollFirst() {       int h = head;       ("unchecked")       E result = (E) elements[h];       // Element is null if deque empty       if (result == null)           return null;//删除头元素       elements[h] = null;     // Must null out slot//更改head下标,处理越界情况让head=0       head = (h + 1) & (elements.length - 1);       return result;   }

   public E pollLast() {//获取tail下标,处理tail=0的特殊情况,移除元素后tail=elements.length-1       int t = (tail - 1) & (elements.length - 1);       ("unchecked")       E result = (E) elements[t];       if (result == null)           return null;       elements[t] = null;//tail指向下个要添加元素的索引       tail = t;       return result;   }

删除指定元素

需要遍历数组,时间复杂度较高

123456789101112131415161718192021222324252627282930313233
   public boolean removeFirstOccurrence(Object o) {       if (o == null)           return false;       int mask = elements.length - 1;       int i = head;       Object x;       while ( (x = elements[i]) != null) {           if (o.equals(x)) {               delete(i);               return true;           }           i = (i + 1) & mask;       }       return false;   }

   public boolean removeLastOccurrence(Object o) {       if (o == null)           return false;       int mask = elements.length - 1;//末尾元素的索引       int i = (tail - 1) & mask;       Object x;       while ( (x = elements[i]) != null) {           if (o.equals(x)) {               delete(i);               return true;           }		//从尾到头遍历           i = (i - 1) & mask;       }       return false;   }
1234567891011121314151617181920212223242526272829303132333435363738394041424344
   private boolean delete(int i) {//检查有效性       checkInvariants();       final Object[] elements = this.elements;       final int mask = elements.length - 1;       final int h = head;       final int t = tail;//i前面的元素       final int front = (i - h) & mask;//i后面的元素       final int back  = (t - i) & mask;

//i不在t和h之间       if (front >= ((t - h) & mask))           throw new ConcurrentModificationException();

       // Optimize for least element motion       if (front < back) {	// head X X i X X X X tail,head-i的元素大于i-tail元素个数           if (h <= i) {               System.arraycopy(elements, h, elements, h + 1, front);           } else { // Wrap around	// i X X X X tail X X head                System.arraycopy(elements, 0, elements, 1, i);               elements[0] = elements[mask];               System.arraycopy(elements, h, elements, h + 1, mask - h);           }           elements[h] = null;           head = (h + 1) & mask;           return false;       } else {	// head X X X X i X X tail           if (i < t) { // Copy the null tail as well               System.arraycopy(elements, i + 1, elements, i, back);               tail = t - 1;           } else { // Wrap around	// tail X X head X X X X i               System.arraycopy(elements, i + 1, elements, i, mask - i);               elements[mask] = elements[0];               System.arraycopy(elements, 1, elements, 0, t);               tail = (t - 1) & mask;           }           return true;       }
12345678910
   private void checkInvariants() {//tail没有元素       assert elements[tail] == null;//head和tail位置重合,队列为空,否则head、tail-1位置有元素       assert head == tail ? elements[head] == null :           (elements[head] != null &&            elements[(tail - 1) & (elements.length - 1)] != null);//head-1的位置没有元素。         assert elements[(head - 1) & (elements.length - 1)] == null;   }

扩容

123456789101112131415161718
   private void doubleCapacity() {//tail和head重合的时候进行扩容,此时tail在head左侧       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到element数组末尾的元素       System.arraycopy(elements, p, a, 0, r);//在复制0到tail之间的元素       System.arraycopy(elements, 0, a, r, p);       elements = a;       head = 0;       tail = n;   }

原文:大专栏  java源码解读--queue

原文地址:https://www.cnblogs.com/petewell/p/11588764.html

时间: 2024-11-23 22:36:44

java源码解读--queue的相关文章

JAVA源码解读---HashMap目录扩展的奥秘

摘要:为了探索JAVA1.7源码中HashMap类数据的组织方法与目录扩展方法,本文通过对JAVA1.7源码中HashMap类源码的阅读与分析,得出结论:hashmap中存储数据的数据结构采用的是链表数组,目录是个数组,数组的成员是链表.冲突解决方法:典型的链地址法,冲突后,在链表头部插入数据.目录扩展方法:已二倍的方式扩展,一直到目录的最大上限.目录扩展的触发条件:装载因子的方式触发.从java中hashmap的实现可以看出,桶数据的组织方式并不是一种非常高效的方式.对检索效率不利.同时,数据

Java源码解读系列(一):ArrayList

本文简单介绍了 ArrayList,并对扩容,添加,删除操作的源代码做分析.能力有限,欢迎指正. ArrayList是什么? ArrayList 就是数组列表,主要用来装载数据.底层实现是数组 Object[] elementData,当我们装载的是基本数据类型 int, long, boolean, shot...的时候我们只能存储他们对应的包装类型. 与它类似的是 LinkedList,和 LinkedList 相比,它的查找和访问元素的速度较快,但新增,删除的速度较慢. 线程安全吗? 线程

Java之ArrayList源码解读(JDK 1.8)

java.util.ArrayList 详细注释了ArrayList的实现,基于JDK 1.8 . 迭代器SubList部分未详细解释,会放到其他源码解读里面.此处重点关注ArrayList本身实现. 没有采用标准的注释,并适当调整了代码的缩进以方便介绍 import java.util.AbstractList; import java.util.Arrays; import java.util.BitSet; import java.util.Collection; import java.

【源码阅读】Java集合 - ArrayList深度源码解读

Java 源码阅读的第一步是Collection框架源码,这也是面试基础中的基础: 针对Collection的源码阅读写一个系列的文章,从ArrayList开始第一篇. [email protected] JDK版本 JDK 1.8.0_110 概述总结 ArrayList底层是通过数组实现的:其中capacity表示底层数组的长度,而ArrayList长度由size表示: ArrayList允许存放null元素,也可以查找null所在的index, 比如indexOf(), lastIndex

Gson 源码解读

开源库地址:https://github.com/google/gson 解读版本:2.7 Gson是一个可以用来将Java对象转换为JSON字符串的Java库.当然,它也可以把JSON字符串转换为等价的Java对象.网上已经有了不少可将Java对象转换成JSON的开源项目.但是,大多数都要求你在Java类中加入注解,如果你无法修改源码的话就比较坑爹了,此外大多数开源库并没有对泛型提供完全的支持.于是,Gson在这两个重要的设计目标下诞生了.Gson可以作用于任意的Java对象(包括接触不到源码

solr源码解读(转)

solr源码解读(转)原文地址:http://blog.csdn.net/duck_genuine/article/details/6962624 配置 solr 对一个搜索请求的的流程 在solrconfig.xml会配置一个handler.配置了前置处理组件preParams,还有后置处理组件filterResult,当然还有默认的组件 [html] view plaincopy <requestHandler name="standard" class="solr

AsyncTask异步任务 源码解读

之前我们介绍了Handler的一些基本用法,也解读了Handler的源码.通过Handler我们可以简便的切换到主线程进行UI操作.而AsyncTask的出现使我们不用去关心线程管理和切换的一些细节,我们可以更轻松的去操作UI. 基本概念 AsyncTask异步任务的作用 AsyncTask,见名之意,异步任务.允许我们在后台做一些耗时操作,然后切换到主线程更新,而且这一过程变得非常简便.一提到异步任务,我们的第一反应就是多线程.假如我们现在需要去下载一张图片,然后在界面上显示,如果没有Asyn

AFNetworking 3.0 源码解读 总结

终于写完了 AFNetworking 的源码解读.这一过程耗时数天.当我回过头又重头到尾的读了一篇,又有所收获.不禁让我想起了当初上学时的种种情景.我们应该对知识进行反复的记忆和理解.下边是我总结的 AFNetworking 中能够学到的知识点. 1.枚举(enum) 使用原则:当满足一个有限的并具有统一主题的集合的时候,我们就考虑使用枚举.这在很多框架中都验证了这个原则.最重要的是能够增加程序的可读性. 示例代码: /** * 网络类型 (需要封装为一个自己的枚举) */ typedef NS

jdk1.8.0_45源码解读——LinkedList的实现

jdk1.8.0_45源码解读——LinkedList的实现 一.LinkedList概述 LinkedList是List和Deque接口的双向链表的实现.实现了所有可选列表操作,并允许包括null值.    LinkedList既然是通过双向链表去实现的,那么它可以被当作堆栈.队列或双端队列进行操作.并且其顺序访问非常高效,而随机访问效率比较低. 注意,此实现不是同步的. 如果多个线程同时访问一个LinkedList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步.这通常是通