List接口是Java中常常用到的接口,若是对具体的List实现类的特性不了解的话,可能会致使程序性能的降低,下面从原理上简单的介绍List的具体实现:java
能够看到,List继承了Collection接口,而Collection接口继承了Iterable接口。其中还有AbstractCollection和AbstractList的实现,用于List对象的公共部分代码的复用:数组
public interface List<E> extends Collection<E> { // Query Operations
public interface Collection<E> extends Iterable<E> { // Query Operations
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractList() { }
public abstract class AbstractCollection<E> implements Collection<E> { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractCollection() { }
具体这三个接口定义的方法以下:安全
如今来看看List接口的具体特性:数据结构
一、Vector多线程
Vector类是经过数组实现的,支持线程的同步,即某一时刻只有一个线程可以写Vector,避免多线程同时写而引发的不一致性,但实现同步须要很高的花费,所以,访问它的效率不是很高。并发
如今来看一下Vector的成员变量和其中部分的构造方法:app
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { /** * The array buffer into which the components of the vector are * stored. The capacity of the vector is the length of this array buffer, * and is at least large enough to contain all the vector's elements. * * <p>Any array elements following the last element in the Vector are null. * * @serial */ protected Object[] elementData; /** * The number of valid components in this {@code Vector} object. * Components {@code elementData[0]} through * {@code elementData[elementCount-1]} are the actual items. * * @serial */ protected int elementCount; /** * The amount by which the capacity of the vector is automatically * incremented when its size becomes greater than its capacity. If * the capacity increment is less than or equal to zero, the capacity * of the vector is doubled each time it needs to grow. * * @serial */ protected int capacityIncrement; /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -2767605614048989439L; /** * Constructs an empty vector with the specified initial capacity and * capacity increment. * * @param initialCapacity the initial capacity of the vector * @param capacityIncrement the amount by which the capacity is * increased when the vector overflows * @throws IllegalArgumentException if the specified initial capacity * is negative */ public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
对数据结构有必定了解的人都知道,使用数组做为存储底层,当存储空间不够了的时候,是会从新分配一块更大的内存空间,而后把原空间的数据所有都copy过去,最后释放原空间,这样会致使程序性能的降低,或者是GC的消耗(Vector是默认扩展1倍)。因此咱们对处理的数据量要有必定的预估,初始化Vector的时候指定容量大小。因为对Vector全部动做都添加synchronized关键字,一样会致使执行的性能降低。less
下面是对Vector添加元素的时候的代码:dom
/** * Appends the specified element to the end of this Vector. * * @param e element to be appended to this Vector * @return {@code true} (as specified by {@link Collection#add}) * @since 1.2 */ public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
/** * This implements the unsynchronized semantics of ensureCapacity. * Synchronized methods in this class can internally call this * method for ensuring capacity without incurring the cost of an * extra synchronization. * * @see #ensureCapacity(int) */ private void ensureCapacityHelper(int minCapacity) { int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object[] oldData = elementData; int newCapacity = (capacityIncrement > 0) ? (oldCapacity + capacityIncrement) : (oldCapacity * 2); if (newCapacity < minCapacity) { newCapacity = minCapacity; } elementData = Arrays.copyOf(elementData, newCapacity); } }
二、Stack性能
Stack 类表示后进先出(LIFO)的对象堆栈。它经过五个操做对类 Vector 进行了扩展,一样是线程安全的 ,容许将向量视为堆栈。它提供了一般的 push 和 pop 操做,以及取堆栈顶点的 peek 方法、测试堆栈是否为空的 empty 方法、在堆栈中查找项并肯定到堆栈顶距离的 search 方法。当操做的集合不存在元素的时候,抛出EmptyStackException。
public class Stack<E> extends Vector<E> { /** * Creates an empty Stack. */ public Stack() { }
三、ArrayList
一样,ArrayList内部是经过数组实现的,它容许对元素进行快速随机访问。数组的缺点是每一个元素之间不能有间隔,当数组大小不知足时须要增长存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,须要对数组进行复制、移动、代价比较高(ArrayList在内存不够时默认是扩展50% + 1个)。所以,它适合随机查找和遍历,不适合插入和删除。因为没有添加同步,因此是非线程安全的,执行效率也要比Vector高不少
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * The array buffer into which the elements of the ArrayList are stored. * The capacity of the ArrayList is the length of this array buffer. */ private transient Object[] elementData; /** * The size of the ArrayList (the number of elements it contains). * * @serial */ private int size; /** * Constructs an empty list with the specified initial capacity. * * @param initialCapacity the initial capacity of the list * @exception IllegalArgumentException if the specified initial capacity * is negative */ public ArrayList(int initialCapacity) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; }
public void ensureCapacity(int minCapacity) { modCount++; int oldCapacity = elementData.length; if (minCapacity > oldCapacity) { Object oldData[] = elementData; int newCapacity = (oldCapacity * 3)/2 + 1; if (newCapacity < minCapacity) newCapacity = minCapacity; // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); } }
四、LinkedList
LinkedList是用双向链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操做表头和表尾元素,能够看成堆栈、队列和双向队列使用。
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable { private transient Entry<E> header = new Entry<E>(null, null, null); private transient int size = 0; /** * Constructs an empty list. */ public LinkedList() { header.next = header.previous = header; }
Entry(E element, Entry<E> next, Entry<E> previous) { this.element = element; this.next = next; this.previous = previous; } }
总结:根据不一样实现类的特性,选择对应的数据结构,能提升程序的运行效率 。须要注意的是,一条线程在进行list列表元素迭代的时候,另一条线程若是想要在迭代过程当中,想要对元素进行操做的时候,好比知足条件添加新元素,会发生ConcurrentModificationException并发修改异常。固然后来版本的CopyOnWrite容器解决了该问题,后续会介绍。