Collection接口是JCF的基础接口,定义了容器类的一些基本操作。
Collection接口常用操作:
int size() boolean isEmpty() | 判断集合中元素的多少 |
boolean contains(Object element) boolean containsAll(Collection c) | 判断集合中是否包含指定的元素 |
boolean add(Object element) bolean remove(Object element) boolean addAll(Collection c) boolean removeAll(Collection c) boolean retainAll(Collection c) void clear() | 在集合中增加或删除元素 |
Iterator iterator() | 返回一个迭代器类,用于遍历集合中的元素 |
Object[] toArray() Object[] toArray(Object a[]) | 进行数据的转换 |
ArrayList与Vector
![](https://img-my.csdn.net/uploads/201204/15/1334494805_4119.jpg)
AbstractList
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
protected transient int modCount = 0;
//创建迭代器的方法
public Iterator<E> iterator() {
return new Itr();
}
//通过内部类来实现迭代器
private class Itr implements Iterator<E> {
//下一次调用next返回的元素的索引。
int cursor = 0;
//最近一次调用next或previous返回的索引
int lastRet = -1;
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size();
}
//得到下一个元素
public E next() {
checkForComodification();
try {
E next = get(cursor);
lastRet = cursor++;
return next;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
//删除cursor当前指向的元素
public void remove() {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.remove(lastRet);
if (lastRet < cursor)
cursor--;
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
}
以上是
AbstrackList中普通Iterator的实现代码,是通过内部类来实现的。
public interface ListIterator<E> extends Iterator<E> {
//判断是否还有下一个元素
boolean hasNext();
//获得下一个元素
E next();
//判断当前位置的前一个位置是否还有元素
boolean hasPrevious();
//得到前置元素
E previous();
//得到下一个元素的索引
int nextIndex();
//得到前一个元素的索引
int previousIndex();
//删除cursor指向的元素
void remove();
//用所给元素替换最后一次调用next()或者最后一次调用previous()所得到的元素
void set(E o);
//向List中添加元素,如果next()操作继续返回元素,那么会插入到该返回元素之前,如果previous()操作继续返回元素,那么会插入到返回元素之后
void add(E o);
}
需要注意的是
ListIterator中索引的意义:
^ ^ ^ ^ ^
Index: 0 1 2 3 n+1
AbstrackList中对 ListIterator接口的实现也是通过内部类,来看一下:
private class ListItr extends Itr implements ListIterator<E> {
ListItr(int index) {
cursor = index;//注意此处索引的意义
}
public boolean hasPrevious() {
return cursor != 0;
}
public E previous() {
checkForComodification();
try {
int i = cursor - 1;
E previous = get(i);
lastRet = cursor = i;
return previous;
} catch(IndexOutOfBoundsException e) {
checkForComodification();
throw new NoSuchElementException();
}
}
public int nextIndex() {
return cursor;
}
public int previousIndex() {
return cursor-1;
}
public void set(E o) {
if (lastRet == -1)
throw new IllegalStateException();
checkForComodification();
try {
AbstractList.this.set(lastRet, o);
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
public void add(E o) {
checkForComodification();
try {
AbstractList.this.add(cursor++, o);
lastRet = -1;
expectedModCount = modCount;
} catch(IndexOutOfBoundsException e) {
throw new ConcurrentModificationException();
}
}
}
它继承了普通Iterator的实现内部类。
AbstrackList中方法的方法中对元素的操作都是通过其实现的两个迭代器来实现的。
ArrayList与Vector
ArrayList与Vector实际上都是是可以动态增长的数组。其最大的区别在于Vector是线程安全的,ArrayList非线程安全的。
下面来看看ArrayList的实现代码:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable{
//transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。
private transient E[] elementData;
//元素个数
private int size;
//可以指定初始容量的构造方法
public ArrayList(int initialCapacity) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity);
//从这一句可以看出其内部结构为一个Object数组
this.elementData = (E[])new Object[initialCapacity];
}
//如不指定初始容量,则默认为10
public ArrayList() {
this(10);
}
//复制另一个容器中的元素来创建对象
public ArrayList(Collection<? extends E> c) {
size = c.size();
// Allow 10% room for growth
elementData = (E[])new Object[
(int)Math.min((size*110L)/100,Integer.MAX_VALUE)];
c.toArray(elementData);
}
//如果空间不足,则重新分配空间,然后将数据复制到新的空间中
//从这个方法看来,ArrayList空间的动态增长代价还是挺高的
public void ensureCapacity(int minCapacity) {
modCount++;
int oldCapacity = elementData.length;
if (minCapacity > oldCapacity) {
Object oldData[] = elementData;
//空间默认增长50%
int newCapacity = (oldCapacity * 3)/2 + 1;
if (newCapacity < minCapacity)
newCapacity = minCapacity;
elementData = (E[])new Object[newCapacity];
System.arraycopy(oldData, 0, elementData, 0, size);
}
}
//返回某个元素的索引
public int indexOf(Object elem) {
//需要注意的是elem可能为Null,为什么需要分别判断??
if (elem == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (elem.equals(elementData[i]))
return i;
}
return -1;
}
//将容器转化为数组,调用System类中的arrayCopy方法完成转化
public Object[] toArray() {
Object[] result = new Object[size];
System.arraycopy(elementData, 0, result, 0, size);
return result;
}
//删除某个元素
public boolean remove(Object o) {
if (o == null) {//删除为空元素
for (int index = 0; index < size; index++)
if (elementData[index] == null) {
fastRemove(index);
return true;
}
} else {
for (int index = 0; index < size; index++)
if (o.equals(elementData[index])) {
fastRemove(index);
return true;
}
}
return false;
}
private void fastRemove(int index) {
modCount++;
int numMoved = size - index - 1;
if (numMoved > 0)
//被删除元素位置之后的元素前移
System.arraycopy(elementData, index+1, elementData, index, numMoved);
elementData[--size] = null; // Let gc do its work
}
}
Vector与ArrayList的实现代码基本相似,它提供了一个ArrayList所没有的方法:
该方法将Vector中的元素以Enumeration的形式返回:
public Enumeration<E> elements() {
return new Enumeration<E>() {
int count = 0;
public boolean hasMoreElements() {
return count < elementCount;
}
public E nextElement() {
synchronized (Vector.this) {
if (count < elementCount) {
return (E)elementData[count++];
}
}
throw new NoSuchElementException("Vector Enumeration");
}
};
}
Stack
Public class Stack<E> extends Vector<E> {
public Stack() { }
public E push(E item) {
addElement(item);
return item;
}
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
public synchronized E peek() {
int len = size();
if (len == 0)
throw new EmptyStackException();
return elementAt(len - 1);
}
public boolean empty() {
return size() == 0;
}
//这个方法返回某个元素距离栈顶的距离,如果该元素不存在,则返回-1
public synchronized int search(Object o) {
int i = lastIndexOf(o);
if (i >= 0) {
return size() - i;
}
return -1;
}
}
Stack继承Vector,便具备动态增长的功能,同时也可看出它是线程安全的。
这是一个“规矩”的栈,它实现了一个栈最基本的功能,入栈、出栈、判空。这又是个“不规矩”的栈,它继承自Vector,那么它便继承了Vector的方法,
而这些方法不是一个标准的栈本该具备的,比如,可以从栈中删除元素,而标准的栈只能从栈顶删除。
当我们使用new Stack()创建Stack 对象时,得到的栈初始大小为10。
ArrayQueue
ArrayQueue是一个循环队列,它也继承了抽象类AbstractList。
public class ArrayQueue extends AbstractList {
private int capacity;
private Object[] queue;//内部数据结构为Object数组
private int head;//队列头
private int tail;//队列尾
public ArrayQueue(int capacity) {
this.capacity = capacity + 1;
this.queue = new Object[capacity + 1];
this.head = 0;
this.tail = 0;
}
public void resize(int newcapacity) {
int size = size();
if (newcapacity < size)
throw new IndexOutOfBoundsException("Resizing would lose data");
newcapacity++;
if (newcapacity == this.capacity)
return;
Object[] newqueue = new Object[newcapacity];
for (int i = 0; i < size; i++)
newqueue[i] = get(i);
this.capacity = newcapacity;
this.queue = newqueue;
this.head = 0;
this.tail = size;
}
public boolean add(Object o) {//入队列,从尾部添加
queue[tail] = o;
int newtail = (tail + 1) % capacity;//这是一个循环队列,所以要进行模运算
if (newtail == head)
throw new IndexOutOfBoundsException("Queue full");
tail = newtail;
return true; // we did add something
}
public Object remove(int i) {//出队列,从头部删除
if (i != 0)
throw new IllegalArgumentException("Can only remove head of queue");
if (head == tail)
throw new IndexOutOfBoundsException("Queue empty");
Object removed = queue[head];
queue[head] = null;
head = (head + 1) % capacity;//循环队列,需要进行模运算
return removed;
}
public Object get(int i) {
int size = size();
if (i < 0 || i >= size) {
final String msg = "Index " + i + ", queue size " + size;
throw new IndexOutOfBoundsException(msg);
}
int index = (head + i) % capacity;
return queue[index];
}
public int size() {
// Can't use % here because it's not mod: -3 % 2 is -1, not +1.
int diff = tail - head;
if (diff < 0)
diff += capacity;
return diff;
}
}