突破程序員基本功的16課-3(Map,List)

Map和List

Map的key是一個Set,可是Map的value不是一個List,不過能夠將其看作一個List。java

Map的values()方法返回的是map的全部value,可是它不是一個List,而是一個內部類Values數組

HashMap中的特性安全

查看values源代碼:性能

public Collection<V> values() {
        Collection<V> vs = values;
        return (vs != null ? vs : (values = new Values()));
    }

能夠看出,values方法返回的是一個集合:newValues()~!this

該內部類以下:spa

private final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
//返回newValueIterator方法的返回值
            return newValueIterator();
        }
        public int size() {
//返回外部類實例的size實例變量的返回值
            return size;
        }
        public boolean contains(Object o) {
//返回外部類實例的containsValue(o)的返回值
            return containsValue(o);
        }
        public void clear() {
//調用外部類實例的clear方法
            HashMap.this.clear();
        }
}

這個Values類繼承AbstractCollection,可是它卻不算一個集合類,由於它沒有add方法,即不能夠添加元素,不能存儲任何java對象。它的做用是遍歷Map中全部的value線程

遍歷方法iterator():主要是依賴ValueIterator類:code

查看newValueIterator類:對象

查看nextEntry方法:繼承

在TreeMap中方法是相似的,可是因爲它是經過紅黑樹實現的,因此它遍歷的時候仍是利用的二叉樹的特色:查找子節點。。。。再也不敘述

綜上:

Map的values方法返回的是map的全部value,該value是一個不能存儲元素的Collection的實現類,因此程序遍歷該集合便是遍歷map的全部value

Map和List的實現沒有太大的類似之處,就是用法挺像

 

ArrayList和LinkedList

List主要有三個實現類:ArrayList,Vector,LinkedList

Vector

Vector有一個實現類:Stack,它只比Vector多了5個方法,本質上仍是一個Vector,它們是線程安全的,不過已經再也不推薦使用了,從1.6版本開始,已經被Deque取代,它也有一個實現類ArrayDeque,它既有隊列的性質又有棧的性質

Vector基本已被ArrayList取代,它相比ArrayList,優點是線程安全的,不過,使用ArrayList時,也可使用Collection的靜態方法來將其包裝成線程安全的,故Vector再也不敘述

在ArrayList中有一行

private transient Object[] elementData;

它是用來保存集合的元素的數組,經過transient修飾,保證了序列化時不會直接序列化該數組,而是經過ArrayList提供的writeObject和readObject方法來實現定製序列化。

ArrayList和LinkedList性能差別

ArrayList底層採用數組存儲,在數據插入的時候,須要作兩件事:

1:保證ArrayList底冊封裝的數組長度大於集合元素的個數

2:將插入位置以後的全部元素總體向後移動一格

查看源代碼:

public E remove(int index) {
		//若是index大於等於size,拋出異常
		RangeCheck(index);
		modCount++;
		//保證index處的元素
		E oldValue = (E) elementData[index];
		//計算總體搬家的元素個數
		int numMoved = size - index - 1;
		if (numMoved > 0)
			System.arraycopy(elementData, index + 1, elementData, index,
					numMoved);
		//釋放被刪除的元素,讓GC回收
		elementData[--size] = null; // Let gc do its work

		return oldValue;
	}

能夠看出,當向ArrayList添加刪除元素的時候,都須要對數組進行總體搬家,性能較差,可是查找的時候:

直接經過數組取值,性能和數組幾乎同樣好

添加時:

public void add(int index, E element) {
	if (index > size || index < 0)
	    throw new IndexOutOfBoundsException(
		"Index: "+index+", Size: "+size);
//保證ArrayList的底層數組老是能夠保存全部元素
	ensureCapacity(size+1);  // Increments modCount!!
/*將elementData數組中index後面的全部元素向後移動一格,這樣就能夠將index處的位置空出來*/
	System.arraycopy(elementData, index, elementData, index + 1,
			 size - index);
//將新元素放置在index處
	elementData[index] = element;
	size++;
    }

這裏調用了ensureCapacity,源碼以下:

能夠看到ArrayList在超過當前容量時,固定的將新容量擴充至原來的1.5倍

LinkedList本質上是一個雙向鏈表,所以它也是使用內部類Entry來保存數據元素:

private static class Entry<E> {
	//集合的元素
	E element;
//指向下一鏈表節點的引用
	Entry<E> next; 
//指向上一鏈表節點的引用
	Entry<E> previous;
//構造器
	Entry(E element, Entry<E> next, Entry<E> previous) {
	    this.element = element;
	    this.next = next;
	    this.previous = previous;
	}
}

能夠看出Entry表明雙向鏈表的一個節點,element是元素自己的值,另外就是鏈表節點的上/下節點的引用,插入數據時形如:

源碼:

主要用到兩個方法:

entry(index)和addBefore();

emrty(index)是get(int index)的底層實現,因爲底層是鏈表,因此LinkedList必須一個元素一個元素的遍歷,直到找到第index個元素

由此能夠看出每次查找元素都須要遍歷鏈表自己,性能較差,不能像ArrayList同樣直接拿到index處的元素

同時看看get(int index)的源碼,就是對entry方法的簡單封裝

public E get(int index){
    return entry(index).element;
}

再看看單純的插入源碼:

若是隻是單純的插入,LinkedList的性能會很到,可是若是在指定位置插入的話,性能也會受影響,由於它涉及到了查找元素,增長了搜索過程。

刪除也是同理:

先查找,再刪除

具體實現:

private E remove(Entry<E> e) {
	if (e == header)
	    throw new NoSuchElementException();
//先保存要刪除的元素
        E result = e.element;
	e.previous.next = e.next;
	e.next.previous = e.previous;
//將被刪除的兩個元素的引用都置爲空,gc回收
        e.next = e.previous = null;
        e.element = null;
	size--;
	modCount++;
        return result;
    }

能夠看出首先將被刪除元素保存起來,再將被刪除元素的next賦給它上一節點的next,將其previous賦給它next節點的previous,即將它本身自己從鏈表中剔除了,再把它自己置爲null,最後返回以前保存的被刪除元素

整體來看,ArrayList的性能優於LinkedList,除非常常添加元素時,否則優先考慮ArrayList

迭代器

Iterator是一個迭代器接口,用於統一的迭代各類Collention集合,至於各集合返回的Iterator實現類,程序不關心,迭代的方式由各集合的實現類本身實現。

使用Iterator迭代是不要刪除集合中的元素,否則會發生ConcurrentModeficationException

相關文章
相關標籤/搜索