ArrayList类:该类继承list,该类中是单向链表,里面存在一个object[]数组,elementData[],在调用get方法是对数组进行获取elementData[index]的方法,所以使用ArrayList来读取数据,它的效率是非常高的,但是它在add(E)和add(int E)的时候却需要对数组进行扩展,使用System.arraycopy进行数组扩展。
public E get(int index) {
RangeCheck(index);//验证索引是否超过数组长度
return (E) elementData[index];
}
//add(E)方法
public boolean add(E e) {
ensureCapacity(size + 1); // 验证数组是否需要扩容
elementData[size++] = e;
return true;
}
//add(int E)方法
public void add(int index, E element) {
if (index > size || index < 0)
throw new IndexOutOfBoundsException(
"Index: "+index+", Size: "+size);
ensureCapacity(size+1); // 验证数组是否需要扩容
System.arraycopy(elementData, index, elementData, index + 1,
size - index);
elementData[index] = element;
size++;
}
LinkedList类:该类可能很多人都知道它是双链表,那么它究竟是怎么实现的呢?在LinkedList.java文件中有另外一个class Entry
Entry(E element, Entry next, Entry previous) {
this.element = element;
this.next = next;
this.previous = previous;
}
所以在构建整个LinkedList的时候只要一个头head即可构建双链表。即a<->b<->c,由于这种模型的特殊性,所以对LinkedList进行插入的时候只需要改变previous和next的执行就可以了,而无需进行数组的扩容,所以对于LinkedList而言它进行多数据插入和删除的时候具有及高的效率。但是对于查询而言,它则需要进行for循环进行遍历。
public boolean add(E e) {
addBefore(e, header);
return true;
}
调用addBefore方法
private Entry addBefore(E e, Entry entry) {
Entry newEntry = new Entry(e, entry, entry.previous);
newEntry.previous.next = newEntry;
newEntry.next.previous = newEntry;
size++;
modCount++;
return newEntry;
}
从上面可以看出来添加是改变Entry的指针不需要数组扩容看,所以非常方便(删除也一样),但是使用get方法:
public E get(int index) {
return entry(index).element;
}
//调用entry方法
private Entry entry(int index) {
if (index < 0 || index >= size)
throw new IndexOutOfBoundsException("Index: "+index+
", Size: "+size);
Entry e = header;
if (index < (size >> 1)) {//这里是一个小技巧,右移1位,相当于使用了二分法
for (int i = 0; i <= index; i++)
e = e.next;
} else {
for (int i = size; i > index; i--)
e = e.previous;
}
return e;
}
可见在LinkedList中获取一个数据是非常麻烦的事情需要进行for循环。
Vector类:该类和ArrayList的区别与hashtable和hashmap的区别一样,它其实实现了ArrayList的线程同步问题。具体代码基本一样。读者可以自己仔细去看看