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<E>该类有三个元素:当前元素,上一级元素,下一级元素
Entry(E element, Entry<E> next, Entry<E> 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<E> addBefore(E e, Entry<E> entry) { Entry<E> newEntry = new Entry<E>(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<E> entry(int index) { if (index < 0 || index >= size) throw new IndexOutOfBoundsException("Index: "+index+ ", Size: "+size); Entry<E> 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的线程同步问题。具体代码基本一样。读者可以自己仔细去看看