1. 程式人生 > >容器Collection

容器Collection

文章目錄


陣列

  • 優勢:是一種簡單的線性序列,可以快速訪問,效率高。從效率和型別檢查角度,陣列是最好的。
  • 劣勢:不靈活,長度初始化時固定了;採用了連續的儲存空間,刪除和新增效率低下;無法儲存直接對映關係;缺乏封裝,操作繁瑣;


集合(Collection)

偷的圖,原作者做好的了,(●ˇ∀ˇ●),請原諒
偷的圖,做的太好了,哈哈




List 介面

  • 有序:使用索引標記元素(底層陣列)
  • 可重複:不同索引位置可使用新增相同元素,即e1.equals(e2)


ArrayList

底層使用陣列實現,查詢效率高,增刪效率低,執行緒不安全。

原始碼學習
/**
 * 繼承 AbstractList,實現 List,即繼承了有序可重複
 * 實現 RandomAccess,可以快速訪問元素
 * 實現 Cloneable,可被複制
 * 實現 Serializable,可被序列化
 * 執行緒不安全的
 */
public class ArrayList<E> extends
AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8683452581122892189L; /** * 預設長度 */ private static final int DEFAULT_CAPACITY = 10; /** * 建構函式使用的預設陣列 */ private static final Object[] EMPTY_ELEMENTDATA = {}; public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); } } /** * 建構函式使用的預設陣列(未傳參) * DEFAULTCAPACITY_EMPTY_ELEMENTDATA 預設大小為10 */ private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; } /** * 底層使用 Object 陣列儲存內容 */ transient Object[] elementData; private int size; }

transient:短暫的,即在物件序列化時,變數不參與序列化


容量不夠時擴容,增加50%

	/**
	* 設定緩衝區大小
	* 先判斷是否為預設陣列,如果是,長度為0,如果不是,minExpand 為0;
	* minCapacity 最小需求容量 > minExpand
	*/
	public void ensureCapacity(int minCapacity) {
        int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
            ? 0
            : DEFAULT_CAPACITY;
        if (minCapacity > minExpand) {
            ensureExplicitCapacity(minCapacity);
        }
    }
    
	/**
	* 設定內部緩衝區大小
	* 先判斷是否為預設陣列,如果是,minCapacity >= 10
	*/    
    private void ensureCapacityInternal(int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        ensureExplicitCapacity(minCapacity);
    }
    
	/**
	* modCount,容量變化次數
	*/
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 先擴容50%,若不夠,直接使用給定的需求容易,若新容量超過陣列的最大限制長度,即限定容量為 Integer.MAX_VALUE,後陣列複製
     */
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//右移位1,即 n/2
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
    
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) 
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
   
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;



LinkedList

LinkedList底層採用雙向連結串列實現儲存,查詢效率低,增刪效率高(底層不需要移動陣列資料,只需修改連結串列節點指標),執行緒不安全
ArrayList比,沒有實現RandomAccess所以其無下標,隨機訪問元素速度較慢
雙向連結串列:也叫雙鏈表,是連結串列的一種,其每個節點都有兩個指標,分別指向前一個節點和後一個節點
LinkedList的儲存結構圖

原始碼學習
/**
 * 繼承 AbstractList,實現 List,即繼承了有序可重複
 * 實現 Deque,可以作為一個雙端佇列
 * 實現 Cloneable,可被複制
 * 執行緒不安全的
 */
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() {
    }

    public LinkedList(Collection<? extends E> c) {
        this();
        addAll(c);
    }
    /**
     * 將集合中的元素全部插入連結串列中
     * 以當前size為下標插入
     */
    public boolean addAll(Collection<? extends E> c) {
        return addAll(size, c);
    }

    public boolean addAll(int index, Collection<? extends E> c) {
        checkPositionIndex(index);

        Object[] a = c.toArray();
        int numNew = a.length;
        if (numNew == 0)
            return false;

        Node<E> pred, succ;		//index節點的前後節點
        if (index == size) {
            succ = null;		//index節點的後節點為null
            pred = last;		//前節點為隊尾
        } else {
            succ = node(index);	//index節點作為後節點
            pred = succ.prev;	//前節點為index的前一個節點
        }
	//連結串列for迴圈遍歷陣列,依次執行插入節點操作
        for (Object o : a) {
            @SuppressWarnings("unchecked") E e = (E) o;
            Node<E> newNode = new Node<>(pred, e, null);
            if (pred == null)
                first = newNode;
            else
                pred.next = newNode;
            pred = newNode;
        }

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

        size += numNew;
        modCount++;
        return true;
    }
	/**
     * 連結串列
     */
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;
        }
    }



Vector

Vector和ArrayList差不多,實現定義基本相同,只是對元素操作的方法都添加了synchronized,保證執行緒的安全
Vector擴容和ArrayList不同,並不是50%,而是若在初始化時未指定擴容容量大小(capacityIncrement=0),則預設擴容一倍,若初始化指定容量大小和擴容容量大小,則擴容按照定義的容量擴容

原始碼學習
	/**
	* 預設大小
	*/
	public Vector() {
        this(10);
    }
    /**
	* 指定預設大小容量-initialCapacity和擴容容量-capacityIncrement
	*/
    public Vector(int initialCapacity, int capacityIncrement) {
        super();
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        this.elementData = new Object[initialCapacity];
        this.capacityIncrement = capacityIncrement;
    }
	/**
	* 容量校驗
	*/
    private void ensureCapacityHelper(int minCapacity) {
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
	/**
	* 若初始化時未指定預設大小容量和擴容容量,即capacityIncrement=0,則預設擴容一倍
	* 若初始化指定容量大小和擴容容量大小,則擴容按照定義容量擴容
	* 然後Arrays.copyOf
	*/
    private void grow(int minCapacity) {
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                         capacityIncrement : oldCapacity);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }



Map 介面

Map採用K-V儲存,通過K鍵標識,K鍵不能重複(鍵重複將會被新資料覆蓋)



HashMap

HashMap底層實現採用了雜湊表,本質是“陣列+連結串列”,因為1.陣列查詢快增刪慢,2.連結串列查詢慢增刪快,所以使用了雜湊表後查詢快增刪也快
JDK8開始,在連結串列大於8時,自動變為紅黑樹
copy的圖
在這裡插入圖片描述

原始碼學習
/**
* 實現 Cloneable ,可以對物件進行位複製,使用clone()方法必須實現其
*/
public class HashMap<K,V> extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable {
    /**
     * 初始化容易大小為16,陣列大小必須為2的冪
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    /**
     * 最大容量為2的30次冪
     */
    static final int MAXIMUM_CAPACITY = 1 << 30;

    /**
     * 預設負載因子-0.75,即陣列被使用超過0.75時,則自動擴容
     */
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    /**
     * 由連結串列轉換成樹的閾值,從JDK8開始,當連結串列在大於8時,自動變為紅黑樹
     */
    static final int TREEIFY_THRESHOLD = 8;

    /**
     * 當小於6時,紅黑樹變為連結串列
     */
    static final int UNTREEIFY_THRESHOLD = 6;

    /**
     * 當元素被樹化時最小的hash表容量,如果沒有達到這個閾值,即hash表容量小於64,當元素太多執行resize擴容操作時,MIN_TREEIFY_CAPACITY至少時TREEIFY_CAPACITY的4倍
     */
    static final int MIN_TREEIFY_CAPACITY = 64;
    /**
     * 核心陣列,預設為16長度
     */
    transient Node<K,V>[] table;
}

Node

	/**
     * Node節點,只有下一個節點指標,所以為單鏈表
     */
    static class Node<K,V> implements Map.Entry<K,V> {
        final int hash;		//雜湊值
        final K key;		
        V value;
        Node<K,V> next;		//下一節點

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }
		/**
		* 判斷兩個節點是否相等
		*/
        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

key能為null

	// 可以有一個null
	static final int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }

紅黑樹

static final class TreeNode<K,V> extends LinkedHashMap.Entry<K,V> {
        TreeNode<K,V> parent;  // 父節點
        TreeNode<K,V> left;
        TreeNode<K,V> right;
        TreeNode<K,V> prev;    // needed to unlink next upon deletion
        boolean red;
        TreeNode(int hash, K key, V val, Node<K,V> next) {
            super(hash, key, val, next);
        }

        /**
         * 返回當前節點的根節點
         */
        final TreeNode<K,V> root() {
            for (TreeNode<K,V> r = this, p;;) {
                if ((p = r.parent) == null)
                    return r;
                r = p;
            }
        }
        //.................
    }

建構函式

	/**
     * 指定初始化容量和負載因子
     */
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
	//指定容量
    public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }
	//預設
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }
	
    public HashMap(Map<? extends K, ? extends V> m) {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        putMapEntries(m, false);
    }
    
    final void putMapEntries(Map<? extends K, ? extends V> m, boolean evict) {
        int s = m.size();
        if (s > 0) {
            if (table == null) { // pre-size
                float ft = ((float)s / loadFactor) + 1.0F;
                int t 
            
           

相關推薦

容器Collection

文章目錄 陣列 集合(Collection) List 介面 ArrayList 原始碼學習 LinkedList

Java基礎(18):集合(容器)—Collection和Map兩大體系介紹和用法

boolean add(E e)_______________________________新增指定元素 boolean addAll(Collection c)___________________將指定集合中所有元素都新增到此 collection boolean contains(Object

java容器類分析:Collection,List,ArrayList

void 但是 exception 3.2 sin .html size hit parameter 1、 Iterable 與 Iterator Iterable 是個接口,實現此接口使集合對象可以通過叠代器遍歷自身元素. public interface Iterabl

Java容器深入淺出之Collection與Iterator介面

Java中用於儲存物件的容器,除了陣列,就是Collection和Map介面下的容器實現類了,包括用於迭代容器中物件的Iterator介面,構成了Java資料結構主體的集合體系。其中包括: 1. Collection:包括Set、List和Queue;主要的實現類有HashSet、TreeSet、Array

Collection容器家族(LinkedHashSet原始碼詳解)

一、在Collection集合體系中的位置及概述         LinkedHashSet 是非同步的有序的,分別是插入順序和訪問順序,LinkedHashSet的有序性可參考LinkedHashMap的有序性,繼承於HashSet,內部基

Collection容器家族(HashSet原始碼詳解)

一、在Collection集合體系中的位置及概述         HashSet繼承自AbstractSet抽象類,實現了Cloneable、Serializable介面,顯示的實現了Set介面。至於為什麼顯示的實現Set介面,我前面的文章講過。

Collection容器家族(Vector講解及Stack原始碼詳解)

Vector講解         Vector類稱作向量類,它實現了動態陣列,用於元素數量變化的物件陣列。像陣列一樣,vector類也用從0開始的下標表示元素的位置;但和陣列不同的是,當vector物件建立後,陣列的元素個數會隨著vector物件元素個數的增大和縮小而自動變

Collection容器家族(TreeSet原始碼詳解)

一、在Collection集合體系中的位置及概述          TreeSet繼承自AbstractSet抽象類,實現了NavigableSet、Serializable、Cloneable、RandomAccess介面。它的特點是儲存元素唯一,無序(輸入和輸出無序)。

Java--容器/集合類(Collection)理解和使用

、陣列和集合的比較 陣列:長度固定,用來存放基本型別的資料 集合:長度不固定,用來存放物件的引用   二、集合類的基本概念 1.java.util包中提供了一些集合類,這些集合類也被稱為容器。 常用的集合有List集合、Set集合、Map集合,他們的關係繼承如下:  

Java學習之容器上(Collection介面常用方法,Iterator介面,使用foreach迴圈遍歷Collection集合元素,Set集合通用知識(Hashset類,hashcode()與Lin

1.容器API的類圖結構如下: JAVA的集合類是一種特別有用的工具類,它可以用於儲存數量不等的多個物件,並可以實現常用資料結構,如棧,佇列等,除此之外,JAVA集合還可用於儲存具有對映關係的關聯陣列。 JAVA的集合大致上可分為:Set,List和Map三

Java入門記(四):容器關係的梳理(上)——Collection

      目錄 三、Set   Java.util中的容器又被稱為Java Collections framework。雖然被稱為框架,但是其主要目的是提供一組介面儘量簡單而且相同、並且儘量高效、以便於開發人員按照場景選用,而不

Java collection 集合 容器 效率問題

下面是關於 集合效率的問題 一萬條一下的資料 差距忽略不計。隨便用誰都行。 List : 可重複 Set : 不可重複 Map: key不可重複 value 可重複 操作 新增 遍歷 隨機查詢 特殊功能 Hash:

JAVA之Collection 集合容器框架(LinkedList,ArrayList,Map等解析)

Java中的集合框架(Collections framework)包含兩個組成:Collection 和Map 一.Collection Collection是一個繼承於Iterable的介面 Collection介面中主要定義了以下常見方法:

Java容器學習筆記(一) 容器中基本概念及Collection介面相關知識

本篇文章主要是總結了java容器中的相關知識點,包括容器層次結構、類圖結構,Collection介面的詳細資訊,以及Collection的一個重要子介面List介面的相關知識點總結。其中涉及到一些類如ArrayList、LinkedList、Vector、Stack、Cop

winform 之MDI容器

for dip each code div ipa rm2 args windows MDI是指將多控件窗體在同一窗體中打開 1、設置:屬性中IsMDIContainer:true; 窗體變為灰色成為MDI窗體容器 2、MDI中一般采用菜單作為打開方式 3、子級窗體在MDI

MDI窗體容器

hide lba contain rm2 open cli tro container logs MDI窗體容器: 一般來說,窗體是頂級容器,不允許放在其他任何容器內,但是如果將某個窗體的IsMdiContainer屬性設置為True,那此窗體就會成為窗體容器,可以在其中放

鏡像的分層結構 - 每天5分鐘玩轉容器技術(11)

數據 9.png upload 問題: 所有 rfi image tle acs Docker 支持通過擴展現有鏡像,創建新的鏡像。 實際上,Docker Hub 中 99% 的鏡像都是通過在 base 鏡像中安裝和配置需要的軟件構建出來的。比如我們現在構建一個新的鏡像,

docker 指定ip開容器,並且和內網在同一個網段

docker 指定ip開機器 並且和內網在同一個網段 docker 指定ip開機器,並且和內網在同一個網段 第1步:創建自定義網絡 備註:這裏選取了100.0.0.0網段,也可以指定其他任意空閑的網段 docker network create --subnet=100.0.

Mybatis Collection查詢集合只出現一條數據

img int ron src per rda entity 級聯 如果 1、原因 如果兩表聯查,主表和明細表的主鍵都是id的話,明細表的多條只能查詢出來第一條。 2、解決辦法 級聯查詢的時候,主表和從表有一樣的字段名的時候,在mysql上命令查詢是沒問

Cocos2d-x中Vector&lt;T&gt;容器以及實例介紹

top 宋體 hello 操作符 模板類 log ins bsp main Vector<T> 是Cocos2d-x 3.x推出的列表容器,因此它所能容納的是Ref及子類所創建的對象指針,其中的T是模板,表示能夠放入到容器中的類型,在Cocos2d-x 3.x