List:有序的序列。此接口的用戶可以對列表中每個元素的插入位置進行精確地控制。用戶可以根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。與 set不同,列表通常允許重複的元素。本文主要介紹4個常用的list接口的子類:Vector,ArrayList,LikedList,Stack
Vector與ArrayList類
Vector 類提供了實現可增長數組的功能,隨着更多元素加入其中,數組變的更大。在刪除一些元素之後,數組變小。它允許存放空指針,它和ArrayList都是用數組實現的,區別就在於Vector是線程安全的,也就是說在多線程中,對於特定的Vector對象,只允許只有一個線程修改它。
ArrayList類與Vector類相似,只是它不提供同步的方法。我們就不分開介紹了,以下是針對Vector的討論。
以下是他的一些基本的方法:
添加元素的方法有:
booleanadd(E o) :將指定元素追加到此向量的末尾。
void add(int index, E element) :在此向量的指定位置插入指定的元素。
void addElement(E obj) :將指定的組件添加到此向量的末尾,將其大小增加 1。
刪除元素的方法:
Eremove(int index) :移除此向量中指定位置的元素。
boolean remove(Object o) :移除此向量中指定元素的第一個匹配項,如果向量不包含該元素,則元素保持不變。
源碼如下:(部分有價值的源碼)
public class Vector<E> extends AbstractList<E> implements List<E>,
RandomAccess, Cloneable, java.io.Serializable {
// 保存數據的數組
protected Object[] elementData;
// 當前的數據量(默認爲10)
protected int elementCount;
// 若數組滿了,那麼數組的長度增長capacityIncrement大小(默認爲零),爲零代表增長
protected int capacityIncrement;
// 數組的最大長度
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
// 構造方法
public Vector(int initialCapacity, int capacityIncrement) {
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "
+ initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
}
public Vector(int initialCapacity) {
this(initialCapacity, 0);
}
public Vector() {
this(10);
}
// 設置數組有效數據的大小,我覺得還是要儘量避免使用該方法(呆會講一下爲什麼)
public synchronized void setSize(int newSize) {
modCount++;
if (newSize > elementCount) {
// 令數組具有指定的長度,(沒有那麼多數據,那麼可以用null填充)
// elementCount = newSize;
ensureCapacityHelper(newSize);
} else {
// 若數據的長度大於newSize,則將數據的前newSize取出,剩下的清零;
for (int i = newSize; i < elementCount; i++) {
elementData[i] = null;
}
}
elementCount = newSize;
}
// 數組的長度
public synchronized int capacity() {
return elementData.length;
}
// 數據的長度
public synchronized int size() {
return elementCount;
}
public synchronized boolean add(E e) {
modCount++;
// 查看數據的長度是否夠用,如果不夠,需要增長
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = e;
return true;
}
public synchronized E remove(int index) {
modCount++;
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index);
E oldValue = elementData(index);
int numMoved = elementCount - index - 1;
if (numMoved > 0)
System.arraycopy(elementData, index + 1, elementData, index,
numMoved);
elementData[--elementCount] = null; // Let gc do its work
return oldValue;
}
}
注意:
1,setSize()方法就是指定元素的有效位數爲新的長度,沒有那麼多的數據用null填充(基本類型有0或者null字符填充);所以用setSize()後,在用迭代器去遍歷,可能會發生空指針錯誤哦。。。
2,爲什麼更多元素加入其中,數組變的更大。在刪除一些元素之後,數組變小。
答:數組變大,這個早就見識過了,一般都是定義更大(一般是2倍大小)的新數組,將原來的數搬移過去的哈,數組變小呢?其實就是把原來存放數據的移除後(若不是最後一位的數據,還要重新操作數組),將elementData[--elementCount] =null;等待jvm將該空指針銷燬哈。。相當於數組變小了。
3,Vector和arrayList都沒有提供remove()操作,一般是remove(int)或者remove(object);
LinkedList類
LinkedList是用鏈表實現的,都學過c語言的數據結構,大概都能理解鏈表與數組實現的區別在於,鏈表對於數據的插入和刪除更加有效,但是對於隨機訪問數據的效率要低於數組;
其實LinkedList相當好理解,沒有什麼特別需要講解的地方,有什麼問題看下源代碼即可;
備註:(需要定義內部類節點Node);
public class LinkedList<E>
extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable
{
transient int size = 0;
//第一個節點
transient Node<E> first;
//第二個節點
transient Node<E> last;
public LinkedList() {
}
/*
* 第一個節點:前一個節點爲空,(若只有一個元素),下一個節點也爲空;
* 最後一個節點,下一個節點爲空,(若只有一個元素),前一個節點也爲空;
*/
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;
}
}
//添加元素,也就是說在鏈表的最後加入新的元素
public boolean add(E e) {
linkLast(e);
return true;
}
//要注意判斷原先沒有元素的情況哈
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
//指定添加首元素;
public void addFirst(E e) {
linkFirst(e);
}
//要注意判斷原先沒有元素的情況哈
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
//去除第一個元素哈
public E removeFirst() {
final Node<E> f = first;
if (f == null)
throw new NoSuchElementException();
return unlinkFirst(f);
}
private E unlinkFirst(Node<E> f) {
// assert f == first && f != null;
final E element = f.item;
final Node<E> next = f.next;
f.item = null;
f.next = null; // help GC
first = next;
if (next == null)
last = null;
else
next.prev = null;
size--;
modCount++;
return element;
}
}
鏈表我們實在是接觸太多了,沒什麼好講的,如果不清楚,可以看下下邊鏈表的基本的連接圖(網上copy的,懶得畫了):
Stack類
Stack是我們熟知的LIFO(後進先出)的對象堆棧;它繼承了Vector,對其進行擴展,那麼可知它也是基於數組來實現的;一般有push和pop操作;
還記得Vector麼,知道爲什麼數組的類型是protected了麼,哈哈。。。
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;
}
}