java容器之List接口

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;
  }
}








發佈了70 篇原創文章 · 獲贊 2 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章