一、前言
基于mina-core(2.0.4)包中的org.apache.mina.util.CircularQueue继承AbstractList实现可循环Queue,具体实现内容如下所示
二、源码说明
package org.apache.mina.util;@b@@b@import java.io.Serializable;@b@import java.util.AbstractList;@b@import java.util.Arrays;@b@import java.util.NoSuchElementException;@b@import java.util.Queue;@b@@b@public class CircularQueue<E> extends AbstractList<E>@b@ implements Queue<E>, Serializable@b@{@b@ private static final long serialVersionUID = 3993421269224511264L;@b@ private static final int DEFAULT_CAPACITY = 4;@b@ private final int initialCapacity;@b@ private volatile Object[] items;@b@ private int mask;@b@ private int first;@b@ private int last;@b@ private boolean full;@b@ private int shrinkThreshold;@b@@b@ public CircularQueue()@b@ {@b@ this(4);@b@ }@b@@b@ public CircularQueue(int initialCapacity)@b@ {@b@ this.first = 0;@b@ this.last = 0;@b@@b@ int actualCapacity = normalizeCapacity(initialCapacity);@b@ this.items = new Object[actualCapacity];@b@ this.mask = (actualCapacity - 1);@b@ this.initialCapacity = actualCapacity;@b@ this.shrinkThreshold = 0;@b@ }@b@@b@ private static int normalizeCapacity(int initialCapacity)@b@ {@b@ int actualCapacity = 1;@b@ do {@b@ if (actualCapacity >= initialCapacity) break label21;@b@ actualCapacity <<= 1; }@b@ while (actualCapacity >= 0);@b@ actualCapacity = 1073741824;@b@@b@ label21: return actualCapacity;@b@ }@b@@b@ public int capacity()@b@ {@b@ return this.items.length;@b@ }@b@@b@ public void clear()@b@ {@b@ if (!(isEmpty())) {@b@ Arrays.fill(this.items, null);@b@ this.first = 0;@b@ this.last = 0;@b@ this.full = false;@b@ shrinkIfNeeded();@b@ }@b@ }@b@@b@ public E poll()@b@ {@b@ if (isEmpty()) {@b@ return null;@b@ }@b@@b@ Object ret = this.items[this.first];@b@ this.items[this.first] = null;@b@ decreaseSize();@b@@b@ if (this.first == this.last) {@b@ this.first = (this.last = 0);@b@ }@b@@b@ shrinkIfNeeded();@b@ return ret;@b@ }@b@@b@ public boolean offer(E item) {@b@ if (item == null) {@b@ throw new IllegalArgumentException("item");@b@ }@b@@b@ expandIfNeeded();@b@ this.items[this.last] = item;@b@ increaseSize();@b@ return true;@b@ }@b@@b@ public E peek()@b@ {@b@ if (isEmpty()) {@b@ return null;@b@ }@b@@b@ return this.items[this.first];@b@ }@b@@b@ public E get(int idx)@b@ {@b@ checkIndex(idx);@b@ return this.items[getRealIndex(idx)];@b@ }@b@@b@ public boolean isEmpty()@b@ {@b@ return ((this.first == this.last) && (!(this.full)));@b@ }@b@@b@ public int size()@b@ {@b@ if (this.full) {@b@ return capacity();@b@ }@b@@b@ if (this.last >= this.first) {@b@ return (this.last - this.first);@b@ }@b@@b@ return (this.last - this.first + capacity());@b@ }@b@@b@ public String toString()@b@ {@b@ return "first=" + this.first + ", last=" + this.last + ", size=" + size() + ", mask = " + this.mask;@b@ }@b@@b@ private void checkIndex(int idx)@b@ {@b@ if ((idx < 0) || (idx >= size()))@b@ throw new IndexOutOfBoundsException(String.valueOf(idx));@b@ }@b@@b@ private int getRealIndex(int idx)@b@ {@b@ return (this.first + idx & this.mask);@b@ }@b@@b@ private void increaseSize() {@b@ this.last = (this.last + 1 & this.mask);@b@ this.full = (this.first == this.last);@b@ }@b@@b@ private void decreaseSize() {@b@ this.first = (this.first + 1 & this.mask);@b@ this.full = false;@b@ }@b@@b@ private void expandIfNeeded() {@b@ if (this.full)@b@ {@b@ int oldLen = this.items.length;@b@ int newLen = oldLen << 1;@b@ Object[] tmp = new Object[newLen];@b@@b@ if (this.first < this.last) {@b@ System.arraycopy(this.items, this.first, tmp, 0, this.last - this.first);@b@ } else {@b@ System.arraycopy(this.items, this.first, tmp, 0, oldLen - this.first);@b@ System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last);@b@ }@b@@b@ this.first = 0;@b@ this.last = oldLen;@b@ this.items = tmp;@b@ this.mask = (tmp.length - 1);@b@ if (newLen >>> 3 > this.initialCapacity)@b@ this.shrinkThreshold = (newLen >>> 3);@b@ }@b@ }@b@@b@ private void shrinkIfNeeded()@b@ {@b@ int size = size();@b@ if (size <= this.shrinkThreshold)@b@ {@b@ int oldLen = this.items.length;@b@ int newLen = normalizeCapacity(size);@b@ if (size == newLen) {@b@ newLen <<= 1;@b@ }@b@@b@ if (newLen >= oldLen) {@b@ return;@b@ }@b@@b@ if (newLen < this.initialCapacity) {@b@ if (oldLen == this.initialCapacity) {@b@ return;@b@ }@b@@b@ newLen = this.initialCapacity;@b@ }@b@@b@ Object[] tmp = new Object[newLen];@b@@b@ if (size > 0)@b@ if (this.first < this.last) {@b@ System.arraycopy(this.items, this.first, tmp, 0, this.last - this.first);@b@ } else {@b@ System.arraycopy(this.items, this.first, tmp, 0, oldLen - this.first);@b@ System.arraycopy(this.items, 0, tmp, oldLen - this.first, this.last);@b@ }@b@@b@@b@ this.first = 0;@b@ this.last = size;@b@ this.items = tmp;@b@ this.mask = (tmp.length - 1);@b@ this.shrinkThreshold = 0;@b@ }@b@ }@b@@b@ public boolean add(E o)@b@ {@b@ return offer(o);@b@ }@b@@b@ public E set(int idx, E o)@b@ {@b@ checkIndex(idx);@b@@b@ int realIdx = getRealIndex(idx);@b@ Object old = this.items[realIdx];@b@ this.items[realIdx] = o;@b@ return old;@b@ }@b@@b@ public void add(int idx, E o)@b@ {@b@ if (idx == size()) {@b@ offer(o);@b@ return;@b@ }@b@@b@ checkIndex(idx);@b@ expandIfNeeded();@b@@b@ int realIdx = getRealIndex(idx);@b@@b@ if (this.first < this.last) {@b@ System.arraycopy(this.items, realIdx, this.items, realIdx + 1, this.last - realIdx);@b@ }@b@ else if (realIdx >= this.first) {@b@ System.arraycopy(this.items, 0, this.items, 1, this.last);@b@ this.items[0] = this.items[(this.items.length - 1)];@b@ System.arraycopy(this.items, realIdx, this.items, realIdx + 1, this.items.length - realIdx - 1);@b@ }@b@ else {@b@ System.arraycopy(this.items, realIdx, this.items, realIdx + 1, this.last - realIdx);@b@ }@b@@b@ this.items[realIdx] = o;@b@ increaseSize();@b@ }@b@@b@ public E remove(int idx)@b@ {@b@ if (idx == 0) {@b@ return poll();@b@ }@b@@b@ checkIndex(idx);@b@@b@ int realIdx = getRealIndex(idx);@b@ Object removed = this.items[realIdx];@b@@b@ if (this.first < this.last) {@b@ System.arraycopy(this.items, this.first, this.items, this.first + 1, realIdx - this.first);@b@ }@b@ else if (realIdx >= this.first) {@b@ System.arraycopy(this.items, this.first, this.items, this.first + 1, realIdx - this.first);@b@ }@b@ else {@b@ System.arraycopy(this.items, 0, this.items, 1, realIdx);@b@ this.items[0] = this.items[(this.items.length - 1)];@b@ System.arraycopy(this.items, this.first, this.items, this.first + 1, this.items.length - this.first - 1);@b@ }@b@@b@ this.items[this.first] = null;@b@ decreaseSize();@b@@b@ shrinkIfNeeded();@b@ return removed;@b@ }@b@@b@ public E remove() {@b@ if (isEmpty())@b@ throw new NoSuchElementException();@b@@b@ return poll();@b@ }@b@@b@ public E element() {@b@ if (isEmpty())@b@ throw new NoSuchElementException();@b@@b@ return peek();@b@ }@b@}