Java集合框架大匯總

原文地址

Java集合

Java集合框架:是一種工具類,就像是一個容器可以存儲任意數(shù)量的具有共同屬性的對象。

Java集合中成員很豐富,常用的集合有ArrayList,HashMap登馒,HashSet等。線程安全的有Vector馁痴,HashTable谊娇。線程不安全的有LinkedList,TreeMap,ArrayList济欢,HashMap等等赠堵。

集合中用到的數(shù)據(jù)結(jié)構(gòu)有以下幾種:

數(shù)組:最常用的數(shù)據(jù)結(jié)構(gòu)之一。數(shù)組的特點是長度固定法褥,可以用下標(biāo)索引茫叭,并且所有的元素的類型都是一致的。使用時盡量把數(shù)組封裝在一個類里半等,防止數(shù)據(jù)被錯誤的操作弄亂揍愁。

鏈表:是一種由多個節(jié)點組成的數(shù)據(jù)結(jié)構(gòu),并且每個節(jié)點包含有數(shù)據(jù)以及指向下一個節(jié)點的引用杀饵,在雙向鏈表里莽囤,還會有一個指向前一個節(jié)點的引用。例如切距,可以用單向鏈表和雙向鏈表來實現(xiàn)堆棧和隊列朽缎,因為鏈表的兩端都是可以進(jìn)行插入和刪除的動作的。當(dāng)然谜悟,也會有在鏈表的中間頻繁插入和刪除節(jié)點的場景话肖。

樹:是一種由節(jié)點組成的數(shù)據(jù)結(jié)構(gòu),每個節(jié)點都包含數(shù)據(jù)元素葡幸,并且有一個或多個子節(jié)點最筒,每個子節(jié)點指向一個父節(jié)點可以表示層級關(guān)系或者數(shù)據(jù)元素的順序關(guān)系。如果樹的每個子節(jié)點最多有兩個葉子節(jié)點蔚叨,那么這種樹被稱為二叉樹床蜘。二叉樹是一種非常常用的樹形結(jié)構(gòu), 因為它的這種結(jié)構(gòu)使得節(jié)點的插入和刪除都非常高效缅叠。樹的邊表示從一個節(jié)點到另外一個節(jié)點的快捷路徑悄泥。

堆棧:只允許對最后插入的元素進(jìn)行操作(也就是后進(jìn)先出虏冻,Last In First Out – LIFO)肤粱。如果你移除了棧頂?shù)脑兀敲茨憧梢圆僮鞯箶?shù)第二個元素厨相,依次類推领曼。這種后進(jìn)先出的方式是通過僅有的peek(),push()和pop()這幾個方法的強制性限制達(dá)到的。這種結(jié)構(gòu)在很多場景下都非常實用蛮穿,例如解析像(4+2)*3這樣的數(shù)學(xué)表達(dá)式庶骄,把源碼中的方法和異常按照他們出現(xiàn)的順序放到堆棧中,檢查你的代碼看看小括號和花括號是不是匹配的践磅,等等单刁。

隊列:和堆棧有些相似,不同之處在于在隊列里第一個插入的元素也是第一個被刪除的元素(即是先進(jìn)先出)府适。這種先進(jìn)先出的結(jié)構(gòu)是通過只提供peek()羔飞,offer()和poll()這幾個方法來訪問數(shù)據(jù)進(jìn)行限制來達(dá)到的肺樟。例如,排隊等待公交車逻淌,銀行或者超市里的等待列隊等等么伯,都是可以用隊列來表示。

Java集合框架圖

[圖片上傳失敗...(image-4b8b54-1530872801038)]

Imgur

Collection interface

如上圖所示卡儒,Collection接口是最基本的集合接口田柔,它不提供直接的實現(xiàn),Java SDK提供的類都是繼承自Collection的“子接口”如List骨望,Set和Queue硬爆。Collection所代表的是一種規(guī)則,它所包含的元素都必須遵循一條或者多條規(guī)則擎鸠。如有些允許出現(xiàn)重復(fù)元素而有些則不允許重復(fù)摆屯、有些必須要按照順序插入而有些則是散列,有些支持排序但是有些則不支持等等糠亩。

List

List接口是Collection接口下的子接口虐骑。List所代表的是有序的Collection,即它用某種特定的插入順序來維護(hù)元素順序赎线。用戶可以對列表中每個元素的插入位置進(jìn)行精確地控制廷没,同時可以根據(jù)元素的整數(shù)索引(在列表中的位置)訪問元素,并搜索列表中的元素垂寥。實現(xiàn)List接口的集合主要有:ArrayList颠黎、LinkedList、Vector滞项、Stack狭归。

ArrayList

ArrayList基于數(shù)組實現(xiàn),可以通過下標(biāo)索引直接查找到指定位置的元素文判,因此查找效率高过椎,但每次插入或刪除元素,就要大量地移動元素戏仓,插入刪除元素的效率低疚宇。它允許任何符合規(guī)則的元素插入甚至包括null。每一個ArrayList都有一個初始容量(10)赏殃,該容量代表了數(shù)組的大小敷待。隨著容器中的元素不斷增加,容器的大小也會隨著增加仁热。在每次向容器中增加元素的同時都會進(jìn)行容量檢查榜揖,當(dāng)快溢出時,就會進(jìn)行擴容操作(擴容1.5倍)。所以如果我們明確所插入元素的多少举哟,最好指定一個初始容量值钳幅,避免過多的進(jìn)行擴容操作而浪費時間、效率炎滞。

ArrayList擅長于隨機訪問敢艰。同時ArrayList是非同步的,只能用在單線程環(huán)境下册赛,多線程環(huán)境下可以考慮用Collections.synchronizedList(List l)函數(shù)返回一個線程安全的ArrayList類钠导,也可以使用concurrent并發(fā)包下的CopyOnWriteArrayList類。

擴充容量的方法ensureCapacity森瘪。ArrayList在每次增加元素(可能是1個牡属,也可能是一組)時,都要調(diào)用該方法來確保足夠的容量扼睬。當(dāng)容量不足以容納當(dāng)前的元素個數(shù)時逮栅,就設(shè)置新的容量為舊的容量的1.5倍,如果設(shè)置后的新容量還不夠窗宇,則直接新容量設(shè)置為傳入的參數(shù)(也就是所需的容量)措伐,而后用Arrays.copyof()方法將元素拷貝到新的數(shù)組。從中可以看出军俊,當(dāng)容量不夠時侥加,每次增加元素,都要將原來的元素拷貝到一個新的數(shù)組中粪躬,非常之耗時担败,也因此建議在事先能確定元素數(shù)量的情況下,才使用ArrayList镰官,否則建議使用LinkedList提前。

ArrayList的具體實現(xiàn)請參考這里

LinkedList

LinkedList同樣實現(xiàn)List接口,與ArrayList不同的是泳唠,LinkedList是基于雙向鏈表實現(xiàn)的狈网,可以在任何位置進(jìn)行高效地插入和移除操作。但是LinkedList不能隨機訪問警检,它所有的操作都是要按照雙重鏈表的需要執(zhí)行孙援。在列表中索引的操作將從開頭或結(jié)尾遍歷列表(從靠近指定索引的一端)。這樣做的好處就是可以通過較低的代價在List中進(jìn)行插入和刪除操作扇雕。

與ArrayList一樣,LinkedList也是非同步的窥摄。如果多個線程同時訪問一個List镶奉,則必須自己實現(xiàn)訪問同步。一種解決方法是在創(chuàng)建List時構(gòu)造一個同步的List:

List list = Collections.synchronizedList(new LinkedList(…));

LinkedList的具體實現(xiàn)請參考這里

Vector

與ArrayList相似,但是Vector是同步的哨苛。所以說Vector是線程安全的動態(tài)數(shù)組鸽凶。它的操作與ArrayList幾乎一樣。

Vector的具體實現(xiàn)請參考這里

Stack

Stack繼承自Vector建峭,實現(xiàn)一個后進(jìn)先出的堆棧玻侥。Stack提供5個額外的方法使得Vector得以被當(dāng)作堆棧使用∫谡簦基本的push和pop 方法凑兰,還有peek方法得到棧頂?shù)脑兀琫mpty方法測試堆棧是否為空边锁,search方法檢測一個元素在堆棧中的位置姑食。Stack剛創(chuàng)建后是空棧。

Stack的具體實現(xiàn)請參考這里

Set

Set接口繼承了Collection接口茅坛。Set集合中不能包含重復(fù)的元素音半,每個元素必須是唯一的。你只需將元素加入set中贡蓖,重復(fù)的元素會自動移除曹鸠。有三種常見的Set實現(xiàn)——HashSet, TreeSet和LinkedHashSet。如果你需要一個訪問快速的Set斥铺,你應(yīng)該使用HashSet物延;當(dāng)你需要一個排序的Set,你應(yīng)該使用TreeSet仅父;當(dāng)你需要記錄下插入時的順序時叛薯,你應(yīng)該使用LinedHashSet。

HashSet

HashSet是是基于 HashMap 實現(xiàn)的笙纤,底層采用 HashMap 來保存元素,所以它不保證set 的迭代順序耗溜;特別是它不保證該順序恒久不變。add()省容、remove()以及contains()等方法都是復(fù)雜度為O(1)的方法抖拴。由于HashMap中key不可重復(fù),所以HashSet元素不可重復(fù)腥椒“⒄可以存儲null元素,是線程不安全的笼蛛。

TreeSet

TreeSet是一個有序集洒放,基于TreeMap實現(xiàn),是線程不安全的滨砍。

TreeSet底層采用TreeMap存儲往湿,構(gòu)造器啟動時新建TreeMap妖异。TreeSet存儲元素實際為TreeMap存儲的鍵值對為<key,PRESENT>的key;,PRESENT為固定對象:private static final Object PRESENT = new Object().

TreeSet支持兩種兩種排序方式领追,通過不同構(gòu)造器調(diào)用實現(xiàn)

自然排序:

public TreeSet() {
    // 新建TreeMap他膳,自然排序
    this(new TreeMap<E,Object>());
}

Comparator排序:

public TreeSet(Comparator<? super E> comparator) {
    // 新建TreeMap,傳入自定義比較器comparator
    this(new TreeMap<>(comparator));
}

TreeSet支持正向/反向迭代器遍歷和foreach遍歷

// 順序TreeSet:迭代器實現(xiàn)
Iterator iter = set.iterator();
while (iter.hasNext()) {
    System.out.println(iter.next());
    
}

// 順序遍歷TreeSet:foreach實現(xiàn)
for (Integer i : set) {
    System.out.println(i);
}

// 逆序遍歷TreeSet:反向迭代器實現(xiàn)
Iterator iter1 = set.descendingIterator();
while (iter1.hasNext()) {
    System.out.println(iter1.next());
}

LinkedHashSet

LinkedHashSet介于HashSet和TreeSet之間绒窑。哈希表和鏈接列表實現(xiàn)棕孙。基本方法的復(fù)雜度為O(1)些膨。

LinkedHashSet 是 Set 的一個具體實現(xiàn)蟀俊,其維護(hù)著一個運行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序傀蓉,該迭代順序可為插入順序或是訪問順序欧漱。

LinkedHashSet 繼承于 HashSet,并且其內(nèi)部是通過 LinkedHashMap 來實現(xiàn)的葬燎。有點類似于我們之前說的LinkedHashMap 其內(nèi)部是基于 Hashmap 實現(xiàn)的一樣误甚。

如果我們需要迭代的順序為插入順序或者訪問順序,那么 LinkedHashSet 是需要你首先考慮的谱净。

LinkedHashSet 底層使用 LinkedHashMap 來保存所有元素窑邦,因為繼承于 HashSet,所有的方法操作上又與 HashSet 相同壕探,因此 LinkedHashSet 的實現(xiàn)上非常簡單冈钦,只提供了四個構(gòu)造方法,并通過傳遞一個標(biāo)識參數(shù)李请,調(diào)用父類的構(gòu)造器瞧筛,底層構(gòu)造一個 LinkedHashMap 來實現(xiàn),在相關(guān)操作上與父類 HashSet 的操作相同导盅,直接調(diào)用父類 HashSet 的方法即可较幌。

package java.util;

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {

    private static final long serialVersionUID = -2851667679971038690L;

    /**
     * 構(gòu)造一個帶有指定初始容量和加載因子的空鏈表哈希set。
     *
     * 底層會調(diào)用父類的構(gòu)造方法白翻,構(gòu)造一個有指定初始容量和加載因子的LinkedHashMap實例乍炉。
     * @param initialCapacity 初始容量。
     * @param loadFactor 加載因子滤馍。
     */
    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }

    /** 
     * 構(gòu)造一個指定初始容量和默認(rèn)加載因子0.75的新鏈表哈希set岛琼。 
     * 
     * 底層會調(diào)用父類的構(gòu)造方法,構(gòu)造一個指定初始容量和默認(rèn)加載因子0.75的LinkedHashMap實例巢株。 
     * @param initialCapacity 初始容量槐瑞。 
     */  
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }

    /** 
     * 構(gòu)造一個默認(rèn)初始容量16和加載因子0.75的新鏈表哈希set。 
     * 
     * 底層會調(diào)用父類的構(gòu)造方法纯续,構(gòu)造一個默認(rèn)初始容量16和加載因子0.75的LinkedHashMap實例随珠。 
     */  
    public LinkedHashSet() {
        super(16, .75f, true);
    }

    /** 
     * 構(gòu)造一個與指定collection中的元素相同的新鏈表哈希set灭袁。 
     *  
     * 底層會調(diào)用父類的構(gòu)造方法猬错,構(gòu)造一個足以包含指定collection 
     * 中所有元素的初始容量和加載因子為0.75的LinkedHashMap實例窗看。 
     * @param c 其中的元素將存放在此set中的collection。 
     */  
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }

    
    @Override
    public Spliterator<E> spliterator() {
        return Spliterators.spliterator(this, Spliterator.DISTINCT | Spliterator.ORDERED);
    }
}

通過觀察HashMap的源碼我們可以發(fā)現(xiàn):

Hash Map的前三個構(gòu)造函數(shù)倦炒,即訪問權(quán)限為public類型的構(gòu)造函數(shù)均是以HashMap作為實現(xiàn)显沈。而以LinkedHashMap作為實現(xiàn)的構(gòu)造函數(shù)的訪問權(quán)限是默認(rèn)訪問權(quán)限,即包內(nèi)訪問權(quán)限逢唤。

即:在java編程中拉讯,通過new創(chuàng)建的HashSet對象均是以HashMap作為實現(xiàn)基礎(chǔ)。只有在jdk中java.util包內(nèi)的源代碼才可能創(chuàng)建以LinkedHashMap作為實現(xiàn)的HashSet(LinkedHashSet就是通過封裝一個以LinkedHashMap為實現(xiàn)的HashSet來實現(xiàn)的)鳖藕。

只有包含三個參數(shù)的構(gòu)造函數(shù)才是采用的LinkedHashMap作為實現(xiàn)魔慷。

Map

Map與List、Set接口不同著恩,它是由一系列鍵值對組成的集合院尔,提供了key到Value的映射。同時它也沒有繼承Collection喉誊。在Map中它保證了key與value之間的一一對應(yīng)關(guān)系邀摆。也就是說一個key對應(yīng)一個value,所以它不能存在相同的key值伍茄,當(dāng)然value值可以相同栋盹。key可以為空,但是只允許出現(xiàn)一個null敷矫。它的主要實現(xiàn)類有HashMap例获、HashTable、LinkedHashMap曹仗、TreeMap榨汤。

HashMap

HashMap 是 Map 的一個實現(xiàn)類,它代表的是一種鍵值對的數(shù)據(jù)存儲形式整葡。

大多數(shù)情況下可以直接定位到它的值件余,因而具有很快的訪問速度,但遍歷順序卻是不確定的遭居。

HashMap最多只允許一條記錄的鍵為null啼器,允許多條記錄的值為null。遇到key為null的時候俱萍,調(diào)用putForNullKey方法進(jìn)行處理端壳,而對value沒有處理。不保證有序(比如插入的順序)枪蘑、也不保證序不隨時間變化损谦。

jdk 8 之前岖免,其內(nèi)部是由數(shù)組+鏈表來實現(xiàn)的,而 jdk 8 對于鏈表長度超過 8 的鏈表將轉(zhuǎn)儲為紅黑樹照捡。

HashMap非線程安全颅湘,即任一時刻可以有多個線程同時寫HashMap,可能會導(dǎo)致數(shù)據(jù)的不一致栗精。如果需要滿足線程安全闯参,可以用 Collections的synchronizedMap方法使HashMap具有線程安全的能力,或者使用ConcurrentHashMap悲立。

hash數(shù)組的默認(rèn)大小是16鹿寨,而且大小一定是2的指數(shù)

HashMap的具體實現(xiàn)請參考這里

HashTable

Hashtable和HashMap一樣也是散列表,存儲元素也是鍵值對薪夕,底層實現(xiàn)是一個Entry數(shù)組+鏈表脚草。Hashtable繼承于Dictionary類(Dictionary類聲明了操作鍵值對的接口方法),實現(xiàn)Map接口(定義鍵值對接口)原献。HashTable是線程安全的馏慨,它的大部分類都被synchronized關(guān)鍵字修飾。key和value都不可為null嚼贡。

hash數(shù)組默認(rèn)大小是11熏纯,擴充方式是old*2+1

LinkedHashMap

LinkedHashMap繼承自HashMap實現(xiàn)了Map接口≡敛撸基本實現(xiàn)同HashMap一樣(底層基于數(shù)組+鏈表+紅黑樹實現(xiàn))樟澜,不同之處在于LinkedHashMap保證了迭代的有序性。其內(nèi)部維護(hù)了一個雙向鏈表叮盘,解決了 HashMap不能隨時保持遍歷順序和插入順序一致的問題秩贰。
除此之外,LinkedHashMap對訪問順序也提供了相關(guān)支持柔吼。在一些場景下毒费,該特性很有用,比如緩存愈魏。

在實現(xiàn)上觅玻,LinkedHashMap很多方法直接繼承自HashMap,僅為維護(hù)雙向鏈表覆寫了部分方法培漏。

默認(rèn)情況下溪厘,LinkedHashMap的迭代順序是按照插入節(jié)點的順序。也可以通過改變accessOrder參數(shù)的值牌柄,使得其遍歷順序按照訪問順序輸出畸悬。

LinkedHashMap的具體實現(xiàn)請參考這里

TreeMap

TreeMap繼承自AbstractMap抽象類,并實現(xiàn)了SortedMap接口珊佣,如下圖所示:

[圖片上傳失敗...(image-fd7a40-1530872801038)]

TreeMap集合是基于紅黑樹(Red-Black tree)的 NavigableMap實現(xiàn)蹋宦。該集合最重要的特點就是可排序披粟,該映射根據(jù)其鍵的自然順序進(jìn)行排序,或者根據(jù)創(chuàng)建映射時提供的 Comparator 進(jìn)行排序冷冗,具體取決于使用的構(gòu)造方法守屉。

關(guān)于集合的常見問題

List和Map的區(qū)別

都是Java常用的容器,都是接口贾惦。不同的是List存儲的是單列的集合胸梆,Map存儲的是key-value鍵值對的集合敦捧。List中允許出現(xiàn)重復(fù)元素须板,Map中不允許key重復(fù)。List集合是有序的(儲存有序)蓬坡,Map集合是無序的(存儲無序)

Set中的元素不能重復(fù)鞍泉,如何實現(xiàn)肃晚?

Set大多都用的Map接口的實現(xiàn)類來實現(xiàn)的(HashSet基于HashMap實現(xiàn),TreeSet基于TreeMap實現(xiàn)甜奄,LinkedHashSet基于LinkedHashMap實現(xiàn))
在HashMap中通過如下實現(xiàn)來保證key值唯一

 // 1. 如果key 相等  
if (p.hash == hash &&
    ((k = p.key) == key || (key != null && key.equals(k))))
    e = p;
// 2. 修改對應(yīng)的value
   if (e != null) { // existing mapping for key
        V oldValue = e.value;
        if (!onlyIfAbsent || oldValue == null)
            e.value = value;
        afterNodeAccess(e);
        return oldValue;
   }

添加元素的時候,如果key(也對應(yīng)的Set集合的元素)相等窃款,那么則修改value值课兄。而在Set集合中,value值僅僅是一個Object對象罷了(該對象對Set本身而言是無用的)晨继。

也就是說:Set集合如果添加的元素相同時烟阐,是根本沒有插入的(僅修改了一個無用的value值)。從源碼(HashMap)中也看出來紊扬,==和equals()方法都有使用蜒茄!

Vector和ArrayList

相同點:
這兩個類都實現(xiàn)了List接口,他們都是有序的集合(儲存有序)餐屎,底層都用數(shù)組實現(xiàn)檀葛。可以通過索引來獲取某個元素腹缩。允許元素重復(fù)和出現(xiàn)null值屿聋。ArrayList和Vector的迭代器實現(xiàn)都是fail-fast的。

不同點:
vector是線程同步的藏鹊,所以它也是線程安全的润讥,而arraylist是線程異步的,是不安全的伙判。如果不考慮到線程的安全因素象对,一般用arraylist效率比較高。

擴容時宴抚,arraylist擴容1.5倍勒魔,vector擴容2倍(或者擴容指定的大懈ι贰)

ArrayList 和Vector是采用數(shù)組方式存儲數(shù)據(jù),此數(shù)組元素數(shù)大于實際存儲的數(shù)據(jù)以便增加和插入元素冠绢,都允許直接序號索引元素抚吠,但是插入數(shù)據(jù)要設(shè)計到數(shù)組元素移動等內(nèi)存操作,所以索引數(shù)據(jù)快插入數(shù)據(jù)慢弟胀,Vector由于使用了synchronized方法(線程安全)所以性能上比ArrayList要差楷力,LinkedList使用雙向鏈表實現(xiàn)存儲,按序號索引數(shù)據(jù)需要進(jìn)行向前或向后遍歷孵户,但是插入數(shù)據(jù)時只需要記錄本項的前后項即可萧朝,所以插入數(shù)度較快!

Aarraylist和Linkedlist

ArrayList是基于數(shù)組實現(xiàn)的夏哭,LinkedList基于雙向鏈表實現(xiàn)的检柬。

ArrayList它支持以下標(biāo)位置進(jìn)行索引出對應(yīng)的元素(隨機訪問),而LinkedList則需要遍歷整個鏈表來獲取對應(yīng)的元素竖配。因此一般來說ArrayList的訪問速度是要比LinkedList要快的

ArrayList由于是數(shù)組何址,對于刪除和修改而言消耗是比較大(復(fù)制和移動數(shù)組實現(xiàn)),LinkedList是雙向鏈表刪除和修改只需要修改對應(yīng)的指針即可进胯,消耗是很小的用爪。因此一般來說LinkedList的增刪速度是要比ArrayList要快的

LinkedList比ArrayList消耗更多的內(nèi)存,因為LinkedList中的每個節(jié)點存儲了前后節(jié)點的引用胁镐。

對于增加/刪除元素操作

如果增刪都是在末尾來操作(每次調(diào)用的都是remove()和add())偎血,此時ArrayList就不需要移動和復(fù)制數(shù)組來進(jìn)行操作了。如果數(shù)據(jù)量有百萬級的時希停,速度是會比LinkedList要快的烁巫。

如果刪除操作的位置是在中間。由于LinkedList的消耗主要是在遍歷上宠能,ArrayList的消耗主要是在移動和復(fù)制上(底層調(diào)用的是arraycopy()方法亚隙,是native方法)。
LinkedList的遍歷速度是要慢于ArrayList的復(fù)制移動速度的
如果數(shù)據(jù)量有百萬級的時违崇,還是ArrayList要快阿弃。

哪些集合類提供對元素的隨機訪問?

ArrayList羞延、HashMap渣淳、TreeMap和HashTable類提供對元素的隨機訪問。

Enumeration和Iterator接口的區(qū)別

Enumeration的速度是Iterator的兩倍伴箩,也使用更少的內(nèi)存入愧。Enumeration是非常基礎(chǔ)的,也滿足了基礎(chǔ)的需要棺蛛。但是怔蚌,與Enumeration相比,Iterator更加安全旁赊,因為當(dāng)一個集合正在被遍歷的時候桦踊,它會阻止其它線程去修改集合。

Iterator的方法名比Enumeration更科學(xué)
Iterator有fail-fast機制终畅,比Enumeration更安全
Iterator能夠刪除元素籍胯,Enumeration并不能刪除元素

Iterater和ListIterator之間有什么區(qū)別?

我們可以使用Iterator來遍歷Set和List集合离福,而ListIterator只能遍歷List杖狼。
Iterator只可以向前遍歷,而LIstIterator可以雙向遍歷术徊。
ListIterator從Iterator接口繼承本刽,然后添加了一些額外的功能,比如添加一個元素赠涮、替換一個元素、獲取前面或后面元素的索引位置暗挑。

Java中HashMap的key值要是為類對象則該類需要滿足什么條件笋除?

需要同時重寫該類的hashCode()方法和它的equals()方法。

從源碼可以得知炸裆,在插入元素的時候是先算出該對象的hashCode垃它。如果hashcode相等話的。那么表明該對象是存儲在同一個位置上的烹看。
如果調(diào)用equals()方法国拇,兩個key相同,則替換元素
如果調(diào)用equals()方法惯殊,兩個key不相同酱吝,則說明該hashCode僅僅是碰巧相同,此時是散列沖突土思,將新增的元素放在桶子上

重寫了equals()方法务热,就要重寫hashCode()的方法。因為equals()認(rèn)定了這兩個對象相同己儒,而同一個對象調(diào)用hashCode()方法時崎岂,是應(yīng)該返回相同的值的!

HashSet與HashMap

HashSet 實現(xiàn)了 Set 接口闪湾,它不允許集合中有重復(fù)的值冲甘,當(dāng)我們提到 HashSet 時,第一件事情就是在將對象存儲在 HashSet 之前,要先確保對象重寫 equals()和 hashCode()方法江醇,這樣才能比較對象的值是否相等省艳,以確保set中沒有儲存相等的對象。如果我們沒有重寫這兩個方法嫁审,將會使用這個方法的默認(rèn)實現(xiàn)跋炕。

public boolean add(Object o)方法用來在 Set 中添加元素,當(dāng)元素值重復(fù)時則會立即返回 false律适,如果成功添加的話會返回 true辐烂。

HashMap 實現(xiàn)了 Map 接口,Map 接口對鍵值對進(jìn)行映射捂贿。Map 中不允許重復(fù)的鍵纠修。Map 接口有兩個基本的實現(xiàn),HashMap 和 TreeMap厂僧。TreeMap 保存了對象的排列次序扣草,而 HashMap 則不能。HashMap 允許鍵和值為 null颜屠。HashMap 是非 synchronized 的辰妙,但 collection 框架提供方法能保證 HashMap synchronized,這樣多個線程同時訪問 HashMap 時甫窟,能保證只有一個線程更改 Map密浑。

public Object put(Object Key,Object value)方法用來將元素添加到 map 中。

HashMap HashSet
HashMap實現(xiàn)了Map接口 HashSet實現(xiàn)了Set接口
HashMap儲存鍵值對 HashSet僅僅存儲對象
使用put()方法將元素放入map中 使用add()方法將元素放入set中
HashMap中使用鍵對象來計算hashcode值 HashSet使用成員對象來計算hashcode值粗井,對于兩個對象來說hashcode可能相同尔破,所以equals()方法用來判斷對象的相等性,如果兩個對象不同的話浇衬,那么返回false

hashtable與hashmap

相同點:
儲存結(jié)構(gòu)和實現(xiàn)基本相同懒构,都是是實現(xiàn)的Map接口

不同點:
HashTable是同步的,HashMap是非同步的耘擂,需要同步的時候可以ConcurrentHashMap方法

HashMap允許為null胆剧,HashTable不允許為null

繼承不同,HashMap繼承的是AbstractMap梳星,HashTable繼承的是Dictionary

HashMap提供對key的Set進(jìn)行遍歷赞赖,因此它是fail-fast的,但HashTable提供對key的Enumeration進(jìn)行遍歷冤灾,它不支持fail-fast前域。

HashTable是一個遺留類,如果需要保證線程安全推薦使用CocurrentHashMap

HashMap與TreeMap

HashMap通過hashcode對其內(nèi)容進(jìn)行快速查找韵吨,而TreeMap中所有的元素都保持著某種固定的順序匿垄,如果你需要得到一個有序的結(jié)果你就應(yīng)該使用TreeMap(HashMap中元素的排列順序是不固定的)。HashMap中元素的排列順序是不固定的)。

在Map 中插入椿疗、刪除和定位元素漏峰,HashMap 是最好的選擇。但如果您要按自然順序或自定義順序遍歷鍵届榄,那么TreeMap會更好浅乔。使用HashMap要求添加的鍵類明確定義了hashCode()和 equals()的實現(xiàn)。 這個TreeMap沒有調(diào)優(yōu)選項铝条,因為該樹總處于平衡狀態(tài)靖苇。

集合框架中的泛型有什么優(yōu)點?

Java1.5引入了泛型班缰,所有的集合接口和實現(xiàn)都大量地使用它贤壁。泛型允許我們?yōu)榧咸峁┮粋€可以容納的對象類型,因此埠忘,如果你添加其它類型的任何元素脾拆,它會在編譯時報錯。這避免了在運行時出現(xiàn)ClassCastException莹妒,因為你將會在編譯時得到報錯信息名船。泛型也使得代碼整潔,我們不需要使用顯式轉(zhuǎn)換和instanceOf操作符动羽。它也給運行時帶來好處包帚,因為不會產(chǎn)生類型檢查的字節(jié)碼指令。

comparable 和 comparator的不同之處运吓?

comparable接口實際上是出自java.lang包
它有一個 compareTo(Object obj)方法來將objects排序
comparator接口實際上是出自 java.util 包
它有一個compare(Object obj1, Object obj2)方法來將objects排序

如何保證一個集合線程安全?

Vector, Hashtable, Properties 和 Stack 都是同步的類疯趟,所以它們都線程安全的拘哨,可以被使用在多線程環(huán)境中
使用Collections.synchronizedList(list)) 方法,可以保證list類是線程安全的
使用java.util.Collections.synchronizedSet()方法可以保證set類是線程安全的信峻。

TreeMap和TreeSet在排序時如何比較元素倦青?Collections工具類中的sort()方法如何比較元素?

TreeSet要求存放的對象所屬的類必須實現(xiàn)Comparable接口盹舞,該接口提供了比較元素的compareTo()方法产镐,當(dāng)插入元素時會回調(diào)該方法比較元素的大小。

TreeMap要求存放的鍵值對映射的鍵必須實現(xiàn)Comparable接口從而根據(jù)鍵對元素進(jìn)行排序踢步。

Collections工具類的sort方法有兩種重載的形式癣亚,第一種要求傳入的待排序容器中存放的對象比較實現(xiàn)Comparable接口以實現(xiàn)元素的比較;第二種不強制性的要求容器中的元素必須可比較获印,但是要求傳入第二個參數(shù)述雾,參數(shù)是Comparator接口的子類型(需要重寫compare方法實現(xiàn)元素的比較),相當(dāng)于一個臨時定義的排序規(guī)則,其實就是通過接口注入比較元素大小的算法玻孟,也是對回調(diào)模式的應(yīng)用(Java中對函數(shù)式編程的支持)唆缴。

什么是Java優(yōu)先級隊列?

Java PriorityQueue是一個數(shù)據(jù)結(jié)構(gòu)黍翎,它是Java集合框架的一部分面徽。 它是一個隊列的實現(xiàn),其中元素的順序?qū)⒏鶕?jù)每個元素的優(yōu)先級來決定匣掸。 實例化PriorityQueue時趟紊,可以在構(gòu)造函數(shù)中提供比較器。 該比較器將決定PriorityQueue集合實例中元素的排序順序旺聚。

Java hashCode()和equals()方法织阳。

equals()方法用于確定兩個Java對象的相等性。 當(dāng)我們有一個自定義類時砰粹,我們需要重寫equals()方法并提供一個實現(xiàn)唧躲,以便它可以用來找到它的兩個實例之間的相等性。 通過Java規(guī)范碱璃,equals()和hashCode()之間有一個契約弄痹。 它說,“如果兩個對象相等嵌器,即obj1.equals(obj2)為true肛真,那么obj1.hashCode()和obj2.hashCode()必須返回相同的整數(shù)”

無論何時我們選擇重寫equals(),我們都必須重寫hashCode()方法爽航。 hashCode()用于計算位置存儲區(qū)和key蚓让。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市讥珍,隨后出現(xiàn)的幾起案子历极,更是在濱河造成了極大的恐慌,老刑警劉巖衷佃,帶你破解...
    沈念sama閱讀 206,311評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件趟卸,死亡現(xiàn)場離奇詭異,居然都是意外死亡氏义,警方通過查閱死者的電腦和手機锄列,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,339評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來惯悠,“玉大人邻邮,你說我怎么就攤上這事∷甭荩” “怎么了饶囚?”我有些...
    開封第一講書人閱讀 152,671評論 0 342
  • 文/不壞的土叔 我叫張陵帕翻,是天一觀的道長。 經(jīng)常有香客問我萝风,道長嘀掸,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,252評論 1 279
  • 正文 為了忘掉前任规惰,我火速辦了婚禮睬塌,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘歇万。我一直安慰自己揩晴,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 64,253評論 5 371
  • 文/花漫 我一把揭開白布贪磺。 她就那樣靜靜地躺著硫兰,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寒锚。 梳的紋絲不亂的頭發(fā)上劫映,一...
    開封第一講書人閱讀 49,031評論 1 285
  • 那天,我揣著相機與錄音刹前,去河邊找鬼泳赋。 笑死,一個胖子當(dāng)著我的面吹牛喇喉,可吹牛的內(nèi)容都是我干的祖今。 我是一名探鬼主播,決...
    沈念sama閱讀 38,340評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼拣技,長吁一口氣:“原來是場噩夢啊……” “哼千诬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起膏斤,我...
    開封第一講書人閱讀 36,973評論 0 259
  • 序言:老撾萬榮一對情侶失蹤大渤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后掸绞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,466評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡耕捞,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,937評論 2 323
  • 正文 我和宋清朗相戀三年衔掸,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俺抽。...
    茶點故事閱讀 38,039評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡敞映,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出磷斧,到底是詐尸還是另有隱情振愿,我是刑警寧澤捷犹,帶...
    沈念sama閱讀 33,701評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站冕末,受9級特大地震影響萍歉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜档桃,卻給世界環(huán)境...
    茶點故事閱讀 39,254評論 3 307
  • 文/蒙蒙 一枪孩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藻肄,春花似錦蔑舞、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,259評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至州弟,卻和暖如春钧栖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背呆馁。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工桐经, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人浙滤。 一個月前我還...
    沈念sama閱讀 45,497評論 2 354
  • 正文 我出身青樓阴挣,卻偏偏與公主長得像,于是被迫代替她去往敵國和親纺腊。 傳聞我的和親對象是個殘疾皇子畔咧,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,786評論 2 345

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

  • Java集合類可用于存儲數(shù)量不等的對象,并可以實現(xiàn)常用的數(shù)據(jù)結(jié)構(gòu)如棧,隊列等,Java集合還可以用于保存具有映射關(guān)...
    小徐andorid閱讀 1,918評論 0 13
  • 一誓沸、集合入門總結(jié) 集合框架: Java中的集合框架大類可分為Collection和Map;兩者的區(qū)別: 1壹粟、Col...
    程序員歐陽閱讀 11,530評論 2 61
  • 集合類框架的介紹: ![Java 集合類框架](https://upload-images.jianshu.io/...
    LynnGuo閱讀 752評論 0 1
  • 在一個方法內(nèi)部定義的變量都存儲在棧中拜隧,當(dāng)這個函數(shù)運行結(jié)束后,其對應(yīng)的棧就會被回收趁仙,此時洪添,在其方法體中定義的變量將不...
    Y了個J閱讀 4,413評論 1 14
  • 今晚和賈先生騎車出去耍。圍著南湖轉(zhuǎn)了一圈雀费,吃個燒烤干奢,南湖的夜市取締了。繞到銀座吃個燒烤盏袄,天氣熱了都會想坐在店外面...
    薇薇安_b57f閱讀 126評論 0 0