Java集合---大結(jié)局(總結(jié)概括終結(jié)篇)

文章寫(xiě)到這,感覺(jué)該做一個(gè)總結(jié)了,也是時(shí)候結(jié)束了, 最常用的集合類(lèi)基本上已經(jīng)寫(xiě)完了,剩下的就不再繼續(xù)探索了,感興趣的自行研究,應(yīng)該還會(huì)有幾篇番外篇,關(guān)于并發(fā)包JUC中的集合,如currenthashmap等類(lèi)的探索, 不過(guò)要過(guò)段時(shí)間了。

之前的文章都在這里了:

Java集合 ---總體框架及主要接口,抽象類(lèi)分析
Java集合 --- ArrayList底層實(shí)現(xiàn)和原理
Java集合 --- Vector底層實(shí)現(xiàn)和原理
Java集合 --- LinkedList底層實(shí)現(xiàn)和原理
Java集合 --- HashMap底層實(shí)現(xiàn)和原理
Java集合 --- TreeMap底層實(shí)現(xiàn)和原理
Java集合 --- HashSet底層實(shí)現(xiàn)和原理
Java集合 --- TreeSet底層實(shí)現(xiàn)和原理
Java集合 --- LinkedHashMap底層實(shí)現(xiàn)

下面對(duì)上面的文章做一下總結(jié),一些在上面文章中沒(méi)有涉及到的點(diǎn),在詳細(xì)的說(shuō)明一下。

Set和Map的關(guān)系

Set代表一種無(wú)序不可重復(fù)的集合,Map代表一種由多個(gè)Key-Value對(duì)組成的集合。表面上看它們之間似乎沒(méi)有啥關(guān)系,但是Map可以看成是Set的擴(kuò)展。為什么這么說(shuō)呢?看下面的這個(gè)例子:

在Map的方法中有一個(gè)這樣的方法,Set<k> keySet() ,也就是說(shuō)Map中的鍵可以轉(zhuǎn)化成一個(gè)Set集合。如果把value看成key的一個(gè)附屬品,或者把key-value看成是一個(gè)整體,那么Map集合就變成了一個(gè)Set集合。

HashSet和HashMap的關(guān)系

HashSet和HashMap有很多的相似之處,對(duì)于HashSet而言,采用了Hash算法來(lái)決定元素的存儲(chǔ)位置,HashMap而言,將value當(dāng)成了key的附屬品,根據(jù)Key的Hash值來(lái)決定存放的位置。

有一點(diǎn)需要說(shuō)明一下,經(jīng)常聽(tīng)說(shuō),集合存儲(chǔ)的是對(duì)象, 這其實(shí)是不準(zhǔn)確的。準(zhǔn)確來(lái)說(shuō),集合中存儲(chǔ)的其實(shí)是對(duì)象的引用地址或者稱(chēng)為引用變量。而引用地址或者引用變量指向了實(shí)際的java對(duì)象。java集合實(shí)際是引用變量的集合而非java對(duì)象的集合。

通過(guò)之前的源碼解析其實(shí)可以發(fā)現(xiàn),HashMap在存放key-value時(shí),并沒(méi)有過(guò)多的考慮value的內(nèi)容。只是根據(jù)key來(lái)確定key-value對(duì)在數(shù)組中應(yīng)該存放的位置。HashMap的底層是一個(gè)Entry[]數(shù)組,key-value組成了一個(gè)entry。當(dāng)需要向HashMap中添加元素時(shí),首先根據(jù)key的hashcode來(lái)確定在數(shù)組中存放的位置,如果key為null,采用特殊方法進(jìn)行處理,存放在數(shù)組的0號(hào)位置。如果當(dāng)前位置已經(jīng)有元素存在,則遍歷單鏈表,如果兩個(gè)key相等,則用新值替換掉舊值,如果key不相等,則插入到鏈表中。有一點(diǎn)需要說(shuō)明,在jdk8之前,hashmap使用數(shù)組+單鏈表存儲(chǔ),在8后,采用了數(shù)組+鏈表+紅黑樹(shù)存儲(chǔ)。

對(duì)于HashSet要說(shuō)的沒(méi)有太多,HashSet的實(shí)現(xiàn)也是比較的簡(jiǎn)單,它的底層使用HashMap實(shí)現(xiàn)的,只是封裝了一個(gè)HashMap對(duì)象來(lái)存儲(chǔ)所有的集合對(duì)象。

TreeSet和TreeMap的關(guān)系

TreeSet底層采用了一個(gè)NavigableMap來(lái)保存TreeSet集合的元素,但實(shí)際上NavigableMap只是一個(gè)借口,因?yàn)榈讓右廊皇鞘褂肨reeMap來(lái)包含Set集合中的元素。 與HashSet類(lèi)似,TreeSet也是調(diào)用TreeMap的方法來(lái)實(shí)現(xiàn)一些操作。TreeMap的底層是使用“紅黑樹(shù)”的排序二叉樹(shù)來(lái)保存Map中的每個(gè)Entry.關(guān)于TreeMap的實(shí)現(xiàn)在上面的鏈接中有詳細(xì)的解釋?zhuān)?qǐng)自行查閱。

HashSet和HashMap是無(wú)序的,而TreeSet和TreeMap是有序的

ArrayList和LinkedList的關(guān)系

List代表的是一種線性結(jié)構(gòu),ArrayList則是一種順序存儲(chǔ)的線性表,ArrayList底層采用數(shù)組來(lái)保存每個(gè)元素,LinkedList是一種鏈?zhǔn)酱鎯?chǔ)的線性表,本質(zhì)是一個(gè)雙向鏈表。

迭代器Iterator
fast-fail快速失敗機(jī)制

在迭代的過(guò)程中,如果刪除了某一個(gè)元素,collection會(huì)拋出ConcurrentModificationException異常。

為什么會(huì)出現(xiàn)這個(gè)異常呢?
這是因?yàn)樵诘鷷r(shí),某個(gè)線程對(duì)該collection在結(jié)構(gòu)上進(jìn)行了更改,從而產(chǎn)生fail-fast.當(dāng)方法檢測(cè)到對(duì)象修改后,但是不允許這種修改就會(huì)拋出該異常。fail-fast只是一種異常檢測(cè)機(jī)制,JDK并不能保證該機(jī)制一定會(huì)發(fā)生。

通過(guò)一個(gè)demo來(lái)詳細(xì)的說(shuō)明下:

LinkedList<String> list = new LinkedList<String>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");

for (String a : list) {
    System.out.println(a);
    list.remove(2);
}

執(zhí)行上面的代碼便會(huì)拋出 java.util.ConcurrentModificationException;
來(lái)看一下LinkedList remove()方法的源碼:

 //刪除方法
 public E remove(int index) {
        checkElementIndex(index); //驗(yàn)證index是否合法
        return unlink(node(index)); //調(diào)用unlink方法
    }
 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++;   //modCount+1 敲黑板劃重點(diǎn)
        return element;
    }

關(guān)于上面代碼的具體含義請(qǐng)自行查閱上面的文章。 上面代碼在刪除指定位置的元素后將執(zhí)行私有內(nèi)部類(lèi)ListItr中的next()方法,進(jìn)行下一個(gè)元素的遍歷.

//在私有內(nèi)部類(lèi)ListItr中有如下的屬性定義,再進(jìn)行遍歷時(shí),將遍歷對(duì)象的modCount值賦值給了expectedModCount。
private int expectedModCount = modCount;

public E next() {
     checkForComodification();
     if (!hasNext())
         throw new NoSuchElementException();

      lastReturned = next;
      next = next.next;
      nextIndex++;
      return lastReturned.item;
}
final void checkForComodification() {
       if (modCount != expectedModCount)
              throw new ConcurrentModificationException();
 }

運(yùn)行next()方法后,會(huì)先執(zhí)行checkForComodification()方法,判斷modCount與expectedModCount是否相等,不相等則拋出異常。

因?yàn)槭潜闅v對(duì)象單方面改變的modCount值,ListItr并沒(méi)有監(jiān)測(cè)到,所以變?cè)斐闪薽odCount和expectedModCount不相等的情況。于是出現(xiàn)了異常。我的理解是,在使用迭代器進(jìn)行對(duì)象遍歷時(shí),創(chuàng)建了一個(gè)新的引用,而新引用指向了遍歷的對(duì)象,同時(shí)將遍歷對(duì)象的一些屬性賦值給了迭代器對(duì)象。調(diào)用遍歷對(duì)象的方法時(shí),對(duì)象的屬性發(fā)生變化,而迭代器對(duì)象中的遍歷對(duì)象的拷貝唯有進(jìn)行更新,導(dǎo)致了值得不匹配,從而拋出異常。這只是我的個(gè)人理解,歡迎深入交流。

采用下面的方法就不會(huì)出現(xiàn)該異常,是因?yàn)榈鲗?duì)象進(jìn)行了屬性的更新! 通過(guò)Iterator的方法刪除后,保證了modCount與expectedModCount值的統(tǒng)一。

Iterator<String> iterator = list.iterator();
        while(iterator.hasNext()){
            String str = iterator.next();
            if(str.equals("a")){
                iterator.remove();
            }
        }

集合篇 完結(jié) 。


少年聽(tīng)雨歌樓上,紅燭昏羅帳。  
壯年聽(tīng)雨客舟中,江闊云低,斷雁叫西風(fēng)。
感謝支持!
                                        ---起個(gè)名忒難
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法,類(lèi)相關(guān)的語(yǔ)法,內(nèi)部類(lèi)的語(yǔ)法,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,759評(píng)論 18 399
  • title: java集合框架學(xué)習(xí)總結(jié) tags:集合框架 categories:總結(jié) date: 2017-03...
    行徑行閱讀 1,707評(píng)論 0 2
  • 一、基本數(shù)據(jù)類(lèi)型 注釋 單行注釋?zhuān)?/ 區(qū)域注釋?zhuān)?* */ 文檔注釋?zhuān)?** */ 數(shù)值 對(duì)于byte類(lèi)型而言...
    龍貓小爺閱讀 4,288評(píng)論 0 16
  • 面向?qū)ο笾饕槍?duì)面向過(guò)程。 面向過(guò)程的基本單元是函數(shù)。 什么是對(duì)象:EVERYTHING IS OBJECT(萬(wàn)物...
    sinpi閱讀 1,088評(píng)論 0 4
  • 前面已經(jīng)介紹完了Collection接口下的集合實(shí)現(xiàn)類(lèi),今天我們來(lái)介紹Map接口下的兩個(gè)重要的集合實(shí)現(xiàn)類(lèi)HashM...
    Ruheng閱讀 10,486評(píng)論 2 38