集合的整理

放一張集合關係圖

1、開始

java集合 就像個容器 把多個對象丟進去(所以會有人稱這個爲java的容器)  存在於java.util包下 總的來說由Collection 進行延伸的  也就是根接口

2、Collection接口

繼承Iterable接口

注意:Iterable(java.lang) 和  terator(java.util)區別

Iterable是接口  terator是迭代器  實現Iterable接口  纔可以調用Iterator方法 對象纔可以使用foreach

Iterable 接口在java.lang包下  這個接口下有Iterator<T> iterator();方法  

          Iterator 是迭代器  迭代器有兩個核心的方法  boolean hasNext()和E next()  可以用這個遍歷ArrayList  Set  LinkedList

List<String> str=new ArrayList<>();
str.add("aaa");
str.add("bbbb");
Iterator<String> it=str.iterator();
while(it.hasNext()){
System.err.println("需要先next 然後再remove 否則會報錯 java.lang.IllegalStateException==="+it.next());
it.remove();

Iterator   迭代器  可以一邊遍歷一邊進行刪除操作

Iterable 可以調用Iterator()方法 實現功能返回迭代器Iterator  另外還有增強for循環的方法(forEach(Consumer<? super T> action))

        爲啥Collection不直接實現Iterator而是先實現Iterable

       Iterator接口的核心方法依賴於迭代器當前迭代位置,如果Collection直接實現Iterator接口 會導致集合對象中包含當前迭代位置的數據  當集合被不同方法使用時  迭代位置就不能預置

每一次調用Iterable的Iterator()方法,都會返回一個從頭開始的Iterator對象,各個Iterator對象之間不會相互干擾,這樣保證了可以同時對一個數據結構進行多個遍歷。這是因爲每個循環都是用了獨立的迭代器Iterator對象。(爲啥collection繼承Iterable而不是Iterator)

          繼承Collection接口 的有三個:List Set Queue

3、List  集合 

有序的容器 保持每個元素的插入順序 可以允許重複的對象  可以插入多個null元素  常用的實現類有ArrayList LinkedList Vector

關鍵是查看源代碼

1)ArrayList  

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable

動態數組 可以快速查詢  數組型的集合 有索引查詢比較快 但是刪除後需要重新排序  所以速度比較慢(看下面源碼 )

查詢很快的原因(通過下標進行讀取)

@SuppressWarnings("unchecked")
    E elementData(int index) {
        return (E) elementData[index];
    }

    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

  移除很慢的原因 (刪除之後需要排序)

 public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }
public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
 private void fastRemove(int index) {
        modCount++;
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
//這裏用了這個方法  也就是刪除某個位置元素  後面的往前複製
//public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
        elementData[--size] = null; // clear to let GC do its work
    }

ArrayList插入之前需要判斷容量  進行擴容處理   如果沒有超過容量(初始容量爲10) 增加數據  ArrayList速度還是很快的  超過容量  涉及到 大量數據的複製過程   所以速度會很慢

ArrayList 是非同步的  如果多個線程  在同一個位置對它進行操作   會容易出錯  線程不安全

2)LinkedList

基於鏈表實現的 實現了Deque接口   可以被當做堆棧 隊列或者雙向隊列使用 可以快速插入和刪除  也是線程不安全的

重要的是節點的操作

 public boolean remove(Object o) {
        if (o == null) {
            for (Node<E> x = first; x != null; x = x.next) {
                if (x.item == null) {
                    unlink(x);
                    return true;
                }
            }
        } else {
            for (Node<E> x = first; x != null; x = x.next) {
                if (o.equals(x.item)) {
                    unlink(x);
                    return true;
                }
            }
        }
        return false;
    }
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;
        }
    }
E unlink(Node<E> x) {
        // assert x != null;
        final E element = x.item;
        final Node<E> next = x.next;
        final Node<E> prev = x.prev;

        if (prev == null) {
            first = next;
        } else {
            prev.next = next;
            x.prev = null;
        }

        if (next == null) {
            last = prev;
        } else {
            next.prev = prev;
            x.next = null;
        }

        x.item = null;
        size--;
        modCount++;
        return element;
    }

3)Vector

當集合中有多線程對集合元素進行操作時 用這個   但是現在一般使用CopyOnWriteArrayList 

有synchronized 修飾  可以同步線程安全 允許元素爲null

4、Set集合 

無序  不可重複   只能允許最多爲一個null

1)HashSet

2)TreeSet

5、Queue 隊列集合

Map   映射關係鍵值對存儲

Set  不包含重複元素的Collection 允許爲null 但是有且僅有一個人null

的實現類都是基於Map來實現的  例如HashSet集合裏面有一個方法 HashSet 含有HashMap類型的成員變量map

public HashSet() {
        map = new HashMap<>();
    }

ConcurrentMap和ConcurrentHashMap

HashMap 通過哈希表存儲k-v的鍵值對 允許key 和value爲nullHashMap 的實例有兩個參數影響其性能 初始容量和加載因子

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章