Java中,List列表类与Set集合类的共同源头是Collection接口,而Collection的父接口是Iterable接口,在Collection接口下又实现了三个常用的接口以及一个抽象方法,分别为Queue接口、List接口、Set接口以及AbstractCollection抽象类,它们之间的关系如图:
而今天所讲的AbstractList抽象类及其实现类则是继承自AbstractCollection抽象类,在AbstractList抽象类中封装了对ArrayList类与LinkedList类以及Vector类的共同操作,来给三者重写,下面来分别谈谈其实现类的区别与注意事项,先上图:
ArrayList
ArrayList类是列表的数组表达形式,继承了AbstracterList抽象类以及List接口、Clone接口以及序列化接口,其默认的到存贮大小是10:
private static final int DEFAULT_CAPACITY = 10;
而且每次容量不够扩容时,是扩展到原来的1.5倍的,假如不够的话直接采用要求的容量大小,并调用Arrays的数组复制的方法来复制:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
//新的容量
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
其实现的克隆方法是我们平常意义上的浅克隆,只是在堆区新建了空间用来一个新的ArrayList,但是并没有新建空间来存放里面的元素,里面的元素还是指向的原来的地址,其源码如下:
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
throw new InternalError(e);
}
}
通过以下代码验证:
String s1=new String("1");
String s2=new String("1");
String s3=new String("1");
ArrayList<String> list=new ArrayList<>();
list.add(s1);
list.add(s2);
list.add(s3);
ArrayList<String> list2=(ArrayList<String>)list.clone();
System.out.print(list2.get(0)==list.get(0));
//打印为true
LinkedList
LinkedList类是列表结构的链式表达方式,与ArrayList实现了相同的接口,它的内部节点的结构如下:
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next) {
this.item = element;
this.next = next;
this.prev = prev;
}
}
很简单的链表节点,也定义了first、last以及size来分别记录头结点、尾节点以及链表的节点大小:
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
同时可以把LinkedList当做栈来使用,因为其方法里含有这两个方法:
public void push(E e) {
addFirst(e);
}
public E pop() {
return removeFirst();
}
也实现了队列:
public E peek() {
final Node<E> f = first;
return (f == null) ? null : f.item;
}
public E element() {
return getFirst();
}
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
push时从头结点压入,而pop时也从头结点取出,也就是实现了栈的先进后出。与ArrayList一样,LinkedList的克隆方法也是一个浅克隆。
Vector
Vector类相当于是ArrayList的线程安全实现,它在需要对元素进行修改的方法加了synchronized关键字,实现了线程安全,比如缩小容量:
public synchronized void trimToSize() {
modCount++;
int oldCapacity = elementData.length;
if (elementCount < oldCapacity) {
elementData = Arrays.copyOf(elementData, elementCount);
}
}
但是Vector的扩容是与ArrayList不一样的,Vector内部多了一个capacityIncrement成员变量,这个变量是由调用者传进来的,可以让程序员自己来定义,Vector每次扩容都会增加capacityIncrement大小:
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}
而Stack类是Vector的子类,在Vector类的基础上实现了元素的先进后出,是一个线程安全类:
public class Stack<E> extends Vector<E> {
public E push(E item) {
// addElement是个同步方法
addElement(item);
return item;
}
public synchronized E pop() {
E obj;
int len = size();
obj = peek();
removeElementAt(len - 1);
return obj;
}
}