Collection集合

概念:對象的容器鼻疮,定義了對多個(gè)對象進(jìn)行操作的常用方法怒坯】眨可實(shí)現(xiàn)數(shù)組的功能。

整體結(jié)構(gòu)圖
List集合

ArrayList擴(kuò)容機(jī)制

  • 當(dāng)new一個(gè)ArrayList時(shí)却邓,實(shí)際是調(diào)用了ArrayList的無參構(gòu)造硕糊,這時(shí)其初始容量為0
  • 在添加第一個(gè)元素時(shí),會將 DEFAULT_CAPACITY 的值作為第一次擴(kuò)容的容量 為10
  • 如果再添加元素腊徙,超過了所擴(kuò)容的容量简十,則會進(jìn)入grow()方法 int newCapacity = oldCapacity + (oldCapacity >> 1); 這句代碼進(jìn)行擴(kuò)容,每次都是原來數(shù)組長度的1.5倍 也就是說撬腾,第二次擴(kuò)容后長度為15
//源碼分析:
package java.util;

import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;


public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * 默認(rèn)初始容量大小
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * 空數(shù)組(用于空實(shí)例)螟蝙。
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

     //用于默認(rèn)大小空實(shí)例的共享空數(shù)組實(shí)例。
      //我們把它從EMPTY_ELEMENTDATA數(shù)組中區(qū)分出來民傻,以知道在添加第一個(gè)元素時(shí)容量需要增加多少胶逢。
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * 保存ArrayList數(shù)據(jù)的數(shù)組
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * ArrayList 所包含的元素個(gè)數(shù)
     */
    private int size;

    /**
     * 帶初始容量參數(shù)的構(gòu)造函數(shù)(用戶可以在創(chuàng)建ArrayList對象時(shí)自己指定集合的初始大小)
     */
    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            //如果傳入的參數(shù)大于0饰潜,創(chuàng)建initialCapacity大小的數(shù)組
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            //如果傳入的參數(shù)等于0初坠,創(chuàng)建空數(shù)組
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            //其他情況,拋出異常
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

    /**
     *默認(rèn)無參構(gòu)造函數(shù)
     *DEFAULTCAPACITY_EMPTY_ELEMENTDATA 為0.初始化為10彭雾,也就是說初始其實(shí)是空數(shù)組 當(dāng)添加第一個(gè)元素的時(shí)候數(shù)組容量才變成10
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }


Set

image.png

HashSet 如何檢查重復(fù)

  • 當(dāng)你把對象加入HashSet時(shí)碟刺,HashSet 會先計(jì)算對象的hashcode值來判斷對象加入的位置,同時(shí)也會與其他加入的對象的 hashcode 值作比較
  • 如果沒有相符的 hashcode薯酝,HashSet 會假設(shè)對象沒有重復(fù)出現(xiàn)半沽。
  • 但是如果發(fā)現(xiàn)有相同 hashcode 值的對象,這時(shí)會調(diào)用equals()方法來檢查 hashcode 相等的對象是否真的相同吴菠。
  • 如果equals()返回true者填,則HashSet 就不會讓加入操作成功。
  • 如果equals()返回false做葵,則形成鏈表

Map

image.png

HashMap

類的屬性
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable {
    // 序列號
    private static final long serialVersionUID = 362498820763181265L;
    // 默認(rèn)的初始容量是16
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;
    // 最大容量
    static final int MAXIMUM_CAPACITY = 1 << 30;
    // 默認(rèn)的填充因子
    static final float DEFAULT_LOAD_FACTOR = 0.75f;
    // 當(dāng)桶(bucket)上的結(jié)點(diǎn)數(shù)大于這個(gè)值時(shí)會轉(zhuǎn)成紅黑樹
    static final int TREEIFY_THRESHOLD = 8;
    // 當(dāng)桶(bucket)上的結(jié)點(diǎn)數(shù)小于這個(gè)值時(shí)樹轉(zhuǎn)鏈表
    static final int UNTREEIFY_THRESHOLD = 6;
    // 桶中結(jié)構(gòu)轉(zhuǎn)化為紅黑樹對應(yīng)的table的最小大小
    static final int MIN_TREEIFY_CAPACITY = 64;
    // 存儲元素的數(shù)組占哟,總是2的冪次倍
    transient Node<k,v>[] table;
    // 存放具體元素的集
    transient Set<map.entry<k,v>> entrySet;
    // 存放元素的個(gè)數(shù),注意這個(gè)不等于數(shù)組的長度。
    transient int size;
    // 每次擴(kuò)容和更改map結(jié)構(gòu)的計(jì)數(shù)器
    transient int modCount;
    // 臨界值 當(dāng)實(shí)際大小(容量*填充因子)超過臨界值時(shí)榨乎,會進(jìn)行擴(kuò)容
    int threshold;
    // 加載因子
    final float loadFactor;
}
HashMap的創(chuàng)建過程
  • HashMap剛創(chuàng)建時(shí)怎燥,table為null(為了節(jié)省空間),當(dāng)添加第一個(gè)元素的時(shí)候蜜暑,table容量調(diào)整為16
  • 當(dāng)元素的個(gè)數(shù)大于閾值(16*0.75=12)時(shí)铐姚,會進(jìn)行擴(kuò)容,擴(kuò)容大小為原來的2倍肛捍。目的是減少調(diào)整元素的個(gè)數(shù)隐绵。
  • jdk1.8 當(dāng)鏈表的長度大于8(將鏈表轉(zhuǎn)換成紅黑樹前會判斷,如果當(dāng)前數(shù)組的長度小于 64拙毫,那么會選擇先進(jìn)行數(shù)組擴(kuò)容依许,而不是轉(zhuǎn)換為紅黑樹)時(shí),會將鏈表轉(zhuǎn)化為紅黑樹恬偷,以減少搜索時(shí)間。
  • jdk1.8 當(dāng)鏈表長度小于6時(shí)帘睦,調(diào)整為鏈表
  • jdk1.8之前袍患,鏈表為頭插入;jdk1.8之后竣付,鏈表為尾插入

HashMap 和 Hashtable 的區(qū)別

  • 線程是否安全: HashMap 是非線程安全的诡延,HashTable 是線程安全的,因?yàn)?HashTable 內(nèi)部的方法基本都經(jīng)過synchronized 修飾。(如果你要保證線程安全的話就使用 ConcurrentHashMap 吧9诺ā)肆良;
  • 效率: 因?yàn)榫€程安全的問題,HashMap 要比 HashTable 效率高一點(diǎn)逸绎。另外惹恃,HashTable 基本被淘汰,不要在代碼中使用它棺牧;
  • 對 Null key 和 Null value 的支持: HashMap 可以存儲 null 的 key 和 value巫糙,但 null 作為鍵只能有一個(gè),null 作為值可以有多個(gè)颊乘;HashTable 不允許有 null 鍵和 null 值参淹,否則會拋出 NullPointerException
  • 初始容量大小和每次擴(kuò)充容量大小的不同 :
    ① 創(chuàng)建時(shí)如果不指定容量初始值乏悄,Hashtable 默認(rèn)的初始大小為 11浙值,之后每次擴(kuò)充,容量變?yōu)樵瓉淼?2n+1檩小。HashMap 默認(rèn)的初始化大小為 16开呐。之后每次擴(kuò)充,容量變?yōu)樵瓉淼?2 倍。
    ② 創(chuàng)建時(shí)如果給定了容量初始值负蚊,那么 Hashtable 會直接使用你給定的大小神妹,而 HashMap 會將其擴(kuò)充為 2 的冪次方大小(HashMap 中的tableSizeFor()方法保證家妆,下面給出了源代碼)鸵荠。也就是說 HashMap 總是使用 2 的冪作為哈希表的大小,后面會介紹到為什么是 2 的冪次方。
  • 底層數(shù)據(jù)結(jié)構(gòu): JDK1.8 以后的 HashMap 在解決哈希沖突時(shí)有了較大的變化伤极,當(dāng)鏈表長度大于閾值(默認(rèn)為 8)(將鏈表轉(zhuǎn)換成紅黑樹前會判斷蛹找,如果當(dāng)前數(shù)組的長度小于 64,那么會選擇先進(jìn)行數(shù)組擴(kuò)容哨坪,而不是轉(zhuǎn)換為紅黑樹)時(shí)庸疾,將鏈表轉(zhuǎn)化為紅黑樹,以減少搜索時(shí)間当编。Hashtable 沒有這樣的機(jī)制

hashCode()與 equals() 的相關(guān)規(guī)定:

  • 如果兩個(gè)對象相等届慈,則 hashcode 一定也是相同的
  • 兩個(gè)對象相等,對兩個(gè) equals() 方法返回 true
  • 兩個(gè)對象有相同的 hashcode 值,它們也不一定是相等的
  • 綜上忿偷,equals() 方法被覆蓋過金顿,則 hashCode() 方法也必須被覆蓋
    hashCode()的默認(rèn)行為是對堆上的對象產(chǎn)生獨(dú)特值。如果沒有重寫 hashCode()鲤桥,則該 class 的兩個(gè)對象無論如何都不會相等(即使這兩個(gè)對象指向相同的數(shù)據(jù))揍拆。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市茶凳,隨后出現(xiàn)的幾起案子嫂拴,更是在濱河造成了極大的恐慌,老刑警劉巖贮喧,帶你破解...
    沈念sama閱讀 211,265評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件筒狠,死亡現(xiàn)場離奇詭異,居然都是意外死亡箱沦,警方通過查閱死者的電腦和手機(jī)窟蓝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評論 2 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來饱普,“玉大人运挫,你說我怎么就攤上這事√赘” “怎么了谁帕?”我有些...
    開封第一講書人閱讀 156,852評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長冯袍。 經(jīng)常有香客問我匈挖,道長碾牌,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,408評論 1 283
  • 正文 為了忘掉前任儡循,我火速辦了婚禮舶吗,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘择膝。我一直安慰自己誓琼,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評論 5 384
  • 文/花漫 我一把揭開白布肴捉。 她就那樣靜靜地躺著腹侣,像睡著了一般。 火紅的嫁衣襯著肌膚如雪齿穗。 梳的紋絲不亂的頭發(fā)上傲隶,一...
    開封第一講書人閱讀 49,772評論 1 290
  • 那天,我揣著相機(jī)與錄音窃页,去河邊找鬼跺株。 笑死,一個(gè)胖子當(dāng)著我的面吹牛脖卖,可吹牛的內(nèi)容都是我干的乒省。 我是一名探鬼主播,決...
    沈念sama閱讀 38,921評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼胚嘲,長吁一口氣:“原來是場噩夢啊……” “哼作儿!你這毒婦竟也來了洛二?” 一聲冷哼從身側(cè)響起馋劈,我...
    開封第一講書人閱讀 37,688評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎晾嘶,沒想到半個(gè)月后妓雾,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡垒迂,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評論 2 325
  • 正文 我和宋清朗相戀三年械姻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片机断。...
    茶點(diǎn)故事閱讀 38,617評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡楷拳,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出吏奸,到底是詐尸還是另有隱情欢揖,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評論 4 329
  • 正文 年R本政府宣布奋蔚,位于F島的核電站她混,受9級特大地震影響烈钞,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坤按,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評論 3 312
  • 文/蒙蒙 一毯欣、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧臭脓,春花似錦酗钞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,740評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至佃扼,卻和暖如春偎巢,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背兼耀。 一陣腳步聲響...
    開封第一講書人閱讀 31,967評論 1 265
  • 我被黑心中介騙來泰國打工压昼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人瘤运。 一個(gè)月前我還...
    沈念sama閱讀 46,315評論 2 360
  • 正文 我出身青樓窍霞,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拯坟。 傳聞我的和親對象是個(gè)殘疾皇子但金,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評論 2 348

推薦閱讀更多精彩內(nèi)容