Java 容器 --- 概述(常見問題補(bǔ)充)

List,Set吮炕,Map三者的區(qū)別?

Java 容器分為 Collection 和 Map 兩大接口祝谚,Collection集合的子接口有Set围小、List昵骤、Queue三種子接口。我們比較常用的是Set肯适、List变秦。

Collection集合主要有List和Set兩大接口:

  • List:基于數(shù)組、鏈表兩種結(jié)構(gòu)實(shí)現(xiàn)框舔,一個(gè)有序(元素存入集合的順序和取出的順序一致)容器蹦玫,元素可以重復(fù),可以插入多個(gè)null元素刘绣。常用的實(shí)現(xiàn)類有 ArrayList樱溉、LinkedList 和 Vector。
  • Set:一個(gè)無序(存入和取出順序有可能不一致)容器纬凤,不可以存儲重復(fù)元素福贞,只允許存入一個(gè)null元素,必須保證元素唯一性停士。Set 接口常用實(shí)現(xiàn)類是 HashSet挖帘、LinkedHashSet 以及 TreeSet(后兩個(gè)可以實(shí)現(xiàn)有序)。

Map是一個(gè)鍵值對集合恋技,存儲鍵拇舀、值之間的映射。

  • Map:Key無序猖任,唯一你稚;value 不要求有序,允許重復(fù)。Map沒有繼承于Collection接口刁赖,從Map集合中檢索元素時(shí)搁痛,只要給出鍵對象,就會返回對應(yīng)的值對象宇弛。Map 的常用實(shí)現(xiàn)類:HashMap鸡典、TreeMap、HashTable枪芒、LinkedHashMap彻况、ConcurrentHashMap
  • Set和Map有基于哈希存儲和紅黑樹實(shí)現(xiàn)。

List舅踪,Set纽甘,Map和Queue的底層數(shù)據(jù)結(jié)構(gòu)

(1)Set

TreeSet:通過 TreeMap 實(shí)現(xiàn)的,添加元素到集合時(shí)按照比較規(guī)則將其插入合適的位置抽碌,保證插入后的集合仍然有序悍赢。但是查找效率不如 HashSet,HashSet 查找的時(shí)間復(fù)雜度為 O(1)货徙,TreeSet 則為 O(logN)左权。

HashSet:通過 HashMap 實(shí)現(xiàn),HashMap 的 Key 即 HashSet 存儲的元素痴颊,所有 Key 都使用相同的 Value 赏迟,一個(gè)名為 PRESENT 的 Object 類型常量。使用 Key 保證元素唯一性蠢棱,但不保證有序性锌杀。由于 HashSet 是 HashMap 實(shí)現(xiàn)的,因此線程不安全裳扯。

LinkedHashSet:繼承自 HashSet抛丽,通過 LinkedHashMap 實(shí)現(xiàn),使用雙向鏈表維護(hù)元素插入順序饰豺。

(2) List

ArrayList:基于動態(tài)數(shù)組實(shí)現(xiàn)亿鲜,支持隨機(jī)訪問。

Vector:和 ArrayList 類似冤吨,但它是線程安全的蒿柳。

LinkedList:基于雙向鏈表實(shí)現(xiàn),只能順序訪問漩蟆,但是可以快速地在鏈表中間插入和刪除元素垒探。不僅如此,LinkedList 還可以用作棧怠李、隊(duì)列和雙向隊(duì)列(刷題常用)圾叼。

(3) Queue

LinkedList:可以用它來實(shí)現(xiàn)雙向隊(duì)列蛤克。

PriorityQueue:基于堆結(jié)構(gòu)實(shí)現(xiàn),可以用它來實(shí)現(xiàn)優(yōu)先隊(duì)列夷蚊。

(4)Map

TreeMap:基于紅黑樹實(shí)現(xiàn)构挤。

HashMap:JDK1.8之前HashMap由數(shù)組+鏈表組成的,數(shù)組是HashMap的主體惕鼓,鏈表則是主要為了解決哈希沖突而存在的(“拉鏈法”解決沖突)筋现。JDK1.8以后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長度大于閾值(默認(rèn)為8)時(shí)箱歧,將鏈表轉(zhuǎn)化為紅黑樹矾飞,以減少搜索時(shí)間

HashTable:和 HashMap 類似,但它是線程安全的呀邢,這意味著同一時(shí)刻多個(gè)線程同時(shí)寫入 HashTable 不會導(dǎo)致數(shù)據(jù)不一致洒沦。它是遺留類,不應(yīng)該去使用它驼鹅,而是使用 ConcurrentHashMap 來支持線程安全微谓,ConcurrentHashMap 的效率會更高,因?yàn)?ConcurrentHashMap 引入了分段鎖输钩。

LinkedHashMap: LinkedHashMap 繼承自 HashMap,所以它的底層仍然是基于拉鏈?zhǔn)缴⒘薪Y(jié)構(gòu)即由數(shù)組和鏈表或紅黑樹組成仲智。LinkedHashMap使用雙向鏈表來維護(hù)元素的順序买乃,順序?yàn)椴迦腠樞蚧蛘咦罱钌偈褂茫↙RU)順序。

comparable和comparator的區(qū)別钓辆?

  • comparable接口實(shí)際上是出自java.lang包剪验,它有一個(gè) compareTo(Object obj)方法用來排序;comparable是一種內(nèi)部自然排序前联,只能有一種定義功戚。接口里只定義了這一個(gè)方法,代表了:傳入一個(gè)對象,將對象和元素自身進(jìn)行比較,如果元素自身大,返回1,相等返回0,元素自身小于參數(shù)則返回-1.
private static class Student implements Comparable {
    int id;
    String name;
    int age;

    @Override
    public int compareTo(Object o) {
        return this.id - ((Student) o).id;
    }
}
  • comparator接口實(shí)際上是出自 java.util 包,它有一個(gè)compare(Object obj1, Object obj2)方法用來排序似嗤;comparator是一種外部比較器啸臀,可以定義多個(gè)不同的比較器,按需取用烁落。功能是對傳入的兩個(gè)元素進(jìn)行大小的比較,并且返回結(jié)果乘粒。
private static class StudentCom1 implements Comparator<Student>{

    @Override
    public int compare(Student o1, Student o2) {
        return o1.id - o2.id;
    }
}

那么問題來了,都有Comparable了,還要Comparator干什么?

設(shè)想一個(gè)場景,我們定義了一個(gè)學(xué)生類,如上面代碼所示,那么學(xué)生可以按著id的大小進(jìn)行排序.

然后現(xiàn)在有兩個(gè)使用的地方,第一個(gè)是考試,需要學(xué)生按照id排序.第二個(gè)是學(xué)生統(tǒng)計(jì),需要學(xué)生按照年齡進(jìn)行排序.

怎么實(shí)現(xiàn)兩種完全不同的排序方式呢?或者更極端一點(diǎn),一會需要按照id增序,一會需要按照id降序呢?改源代碼肯定是不科學(xué)的.

這個(gè)時(shí)候就可以采用以下方案:

  1. 學(xué)生實(shí)現(xiàn)自然排序,即最通用的那種排序方式,比如按照id增序,在需要默認(rèn)排序的情況下,直接調(diào)用學(xué)生的comparTo即可.
  2. 實(shí)現(xiàn)幾個(gè)不同的比較器,比如運(yùn)動會比較器,吃飯比較器等等伤塌,在特定情景下,調(diào)用集合類的排序方法,傳入一個(gè)想要的比較器即可.

總結(jié):一般我們需要對一個(gè)集合使用自定義排序時(shí)灯萍,我們就要重寫compareTo方法或compare方法,當(dāng)我們需要對某一個(gè)集合實(shí)現(xiàn)兩種排序方式每聪,比如一個(gè)song對象中的歌名和歌手名分別采用一種排序方法的話旦棉,我們可以重寫compareTo方法和使用自制的Comparator方法或者以兩個(gè)Comparator來實(shí)現(xiàn)歌名排序和歌星名排序齿风,第二種代表我們只能使用兩個(gè)參數(shù)版的Collections.sort()。

TreeMap和TreeSet在排序時(shí)如何比較元素绑洛?Collections 工具類中的sort()方法如何比較元素救斑?

  • TreeSet 要求存放的對象所屬的類必須實(shí)現(xiàn) Comparable 接口(說明該類是可被排序的),該接口提供了比較元素的 compareTo()方法诊笤,當(dāng)插入元素時(shí)會回調(diào)該方法比較元素的大小系谐。
  • TreeMap 要求存放的鍵值對映射的鍵必須實(shí)現(xiàn) Comparable 接口從而根據(jù)鍵對元素進(jìn)行排序。

Collections 工具類的 sort 方法有兩種重載的形式:

  • 第一種要求傳入的待排序容器中存放的對象要實(shí)現(xiàn) Comparable 接口以實(shí)現(xiàn)元素的比較讨跟;
  • 第二種不強(qiáng)制性的要求容器中的元素必須可比較纪他,但是要求傳入第二個(gè)參數(shù),參數(shù)是Comparator 接口的子類型(需要重寫 compare 方法實(shí)現(xiàn)元素的比較)晾匠,相當(dāng)于一個(gè)臨時(shí)定義的排序規(guī)則茶袒,其實(shí)就是通過接口注入比較元素大小的算法,也是對回調(diào)模式的應(yīng)用(Java 中對函數(shù)式編程的支持)凉馆。

有沒有有順序的Map實(shí)現(xiàn)類薪寓,如果有,他們是怎么實(shí)現(xiàn)有序的澜共?

  • Hashmap和Hashtable 都不是有序的向叉。
  • TreeMap和LinkedHashmap都是有序的。(TreeMap默認(rèn)是key升序嗦董,LinkedHashmap默認(rèn)是數(shù)據(jù)插入順序)

TreeMap是基于比較器Comparator來實(shí)現(xiàn)有序的母谎。LinkedHashmap是基于鏈表來實(shí)現(xiàn)數(shù)據(jù)插入有序的。

我們應(yīng)該如何選用集合?

  • 主要根據(jù)集合的特點(diǎn)來選用京革,比如我們需要根據(jù)鍵值獲取到元素值時(shí)就選?Map接口下的集合奇唤,需要排序時(shí)選擇TreeMap/LinkedHashmap,不需要排序時(shí)就選擇HashMap,需要保證線程安全就選?ConcurrentHashMap.
  • 當(dāng)我們只需要存放元素值時(shí),就選擇實(shí)現(xiàn)Collection接口集合匹摇,需要保證元素唯?時(shí)選擇實(shí)現(xiàn)Set接口的集合咬扇,?如TreeSet或HashSet,不需要就選擇實(shí)現(xiàn)List接口的比如ArrayList或LinkedList廊勃,然后再根據(jù)實(shí)現(xiàn)這些接?的集合的特點(diǎn)來選?懈贺。

綜上所述,選用集合供搀,首先是我們具體的使用場景:只是存值隅居,還是建立一種映射,便于查詢葛虐。其次胎源,考慮集合的元素有序性、元素的唯一性和線程安全性等問題屿脐。

拓展

(1)Collections.sort和Arrays.sort的實(shí)現(xiàn)原理

Collections.sort方法底層就是調(diào)用的Array.sort方法(中間調(diào)用了list.sort涕蚤,然后list.sort調(diào)用了Array.sort方法)

因此宪卿,Arrays的sort方法底層就是:

  • legacyMergeSort(a),歸并排序万栅,
  • ComparableTimSort.sort():即Timsort排序佑钾。Timsort排序是結(jié)合了合并排序(merge.sort)和插入排序(insertion sort)而得出的排序方法;ps:當(dāng)數(shù)組長度小于某個(gè)值烦粒,采用的是二分插入排序算法休溶,插入然后合并。

(2)poll()方法和 remove()方法的區(qū)別扰她?

Queue隊(duì)列中兽掰,poll() 和 remove() 都是從隊(duì)列中取出一個(gè)元素,在隊(duì)列元素為空的情況下:

  • remove() 方法會拋出異常徒役,
  • poll() 方法只會返回 null 孽尽。

(3)HashMap,HashTable忧勿,ConcurrentHash的共同點(diǎn)和區(qū)別

  • 底層都是數(shù)組+鏈表+紅黑樹
  • HashMap可以存儲null鍵和null值杉女,另外兩個(gè)不能存儲null鍵值
  • 。鸳吸。熏挎。

HashMap,LinkedHashMap,TreeMap的區(qū)別

  • Map主要用于存儲健值對,根據(jù)鍵得到值晌砾,因此不允許鍵重復(fù)(重復(fù)了覆蓋了),但允許值重復(fù)婆瓜。Hashmap 是一個(gè)最常用的Map,它根據(jù)鍵的HashCode 值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度贡羔,遍歷時(shí),取得數(shù)據(jù)的順序是完全隨機(jī)的个初。HashMap最多只允許一條記錄的鍵為Null;允許多條記錄的值為 Null;HashMap不支持線程的同步乖寒,即任一時(shí)刻可以有多個(gè)線程同時(shí)寫HashMap;可能會導(dǎo)致數(shù)據(jù)的不一致。如果需要同步院溺,可以用 Collections的synchronizedMap方法使HashMap具有同步的能力楣嘁,或者使用ConcurrentHashMap。
  • Hashtable與 HashMap類似,它繼承自Dictionary類珍逸,不同的是:它不允許記錄的鍵或者值為空;它支持線程的同步逐虚,即任一時(shí)刻只有一個(gè)線程能寫Hashtable,因此也導(dǎo)致了 Hashtable在寫入時(shí)會比較慢。
  • LinkedHashMap保存了記錄的插入順序谆膳,在用Iterator遍歷LinkedHashMap時(shí)叭爱,先得到的記錄肯定是先插入的.也可以在構(gòu)造時(shí)用帶參數(shù),按照應(yīng)用次數(shù)排序漱病。在遍歷的時(shí)候會比HashMap慢买雾,不過有種情況例外把曼,當(dāng)HashMap容量很大,實(shí)際數(shù)據(jù)較少時(shí)漓穿,遍歷起來可能會比LinkedHashMap慢嗤军,因?yàn)長inkedHashMap的遍歷速度只和實(shí)際數(shù)據(jù)有關(guān),和容量無關(guān)晃危,而HashMap的遍歷速度和他的容量有關(guān)叙赚。
  • TreeMap實(shí)現(xiàn)SortMap接口,能夠把它保存的記錄根據(jù)鍵排序,默認(rèn)是按鍵值的升序排序僚饭,也可以指定排序的比較器震叮,當(dāng)用Iterator 遍歷TreeMap時(shí),得到的記錄是排過序的浪慌。

使用場景:

  • 一般情況下冤荆,我們用的最多的是HashMap,HashMap里面存入的鍵值對在取出的時(shí)候是隨機(jī)的,它根據(jù)鍵的HashCode值存儲數(shù)據(jù),根據(jù)鍵可以直接獲取它的值,具有很快的訪問速度权纤。在Map 中插入钓简、刪除和定位元素,HashMap 是最好的選擇汹想。
  • TreeMap取出來的是排序后的鍵值對外邓。但如果您要按自然順序或自定義順序遍歷鍵,那么TreeMap會更好古掏。
  • LinkedHashMap 是HashMap的一個(gè)子類损话,如果需要輸出的順序和輸入的相同,那么用LinkedHashMap可以實(shí)現(xiàn),它還可以按讀取順序來排列,像連接池中可以應(yīng)用槽唾。

總結(jié):

  1. HashSet是通過HashMap實(shí)現(xiàn)的,TreeSet是通過TreeMap實(shí)現(xiàn)的,只不過Set用的只是Map的key
  2. Map的key和Set都有一個(gè)共同的特性就是集合的唯一性.TreeMap更是多了一個(gè)排序的功能.
  3. hashCode和equals()是HashMap用的, 因?yàn)闊o需排序所以只需要關(guān)注定位和唯一性即可.
    a. hashCode是用來計(jì)算hash值的,hash值是用來確定hash表索引的.
    b. hash表中的一個(gè)索引處存放的是一張鏈表, 所以還要通過equal方法循環(huán)比較鏈上的每一個(gè)對象才可以真正定位到鍵值對應(yīng)的Entry.
    c. put時(shí),如果hash表中沒定位到,就在鏈表前加一個(gè)Entry,如果定位到了,則更換Entry中的value,并返回舊value
  4. 由于TreeMap需要排序,所以需要一個(gè)Comparator為鍵值進(jìn)行大小比較.當(dāng)然也是用Comparator定位的.
    a. Comparator可以在創(chuàng)建TreeMap時(shí)指定
    b. 如果創(chuàng)建時(shí)沒有確定,那么就會使用key.compareTo()方法,這就要求key必須實(shí)現(xiàn)Comparable接口.
    c. TreeMap是使用Tree數(shù)據(jù)結(jié)構(gòu)實(shí)現(xiàn)的,所以使用compare接口就可以完成定位了.

巨人的肩膀:

https://blog.csdn.net/xin_jmail/article/details/25975085

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末丧枪,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子庞萍,更是在濱河造成了極大的恐慌拧烦,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,039評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钝计,死亡現(xiàn)場離奇詭異恋博,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)私恬,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,426評論 3 395
  • 文/潘曉璐 我一進(jìn)店門债沮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人本鸣,你說我怎么就攤上這事疫衩。” “怎么了永高?”我有些...
    開封第一講書人閱讀 165,417評論 0 356
  • 文/不壞的土叔 我叫張陵隧土,是天一觀的道長提针。 經(jīng)常有香客問我,道長曹傀,這世上最難降的妖魔是什么辐脖? 我笑而不...
    開封第一講書人閱讀 58,868評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮皆愉,結(jié)果婚禮上嗜价,老公的妹妹穿的比我還像新娘。我一直安慰自己幕庐,他們只是感情好久锥,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,892評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著异剥,像睡著了一般瑟由。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上冤寿,一...
    開封第一講書人閱讀 51,692評論 1 305
  • 那天歹苦,我揣著相機(jī)與錄音,去河邊找鬼督怜。 笑死殴瘦,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的号杠。 我是一名探鬼主播蚪腋,決...
    沈念sama閱讀 40,416評論 3 419
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼姨蟋!你這毒婦竟也來了屉凯?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,326評論 0 276
  • 序言:老撾萬榮一對情侶失蹤眼溶,失蹤者是張志新(化名)和其女友劉穎神得,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體偷仿,經(jīng)...
    沈念sama閱讀 45,782評論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,957評論 3 337
  • 正文 我和宋清朗相戀三年宵蕉,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了酝静。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,102評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡羡玛,死狀恐怖别智,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情稼稿,我是刑警寧澤薄榛,帶...
    沈念sama閱讀 35,790評論 5 346
  • 正文 年R本政府宣布讳窟,位于F島的核電站,受9級特大地震影響敞恋,放射性物質(zhì)發(fā)生泄漏丽啡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,442評論 3 331
  • 文/蒙蒙 一硬猫、第九天 我趴在偏房一處隱蔽的房頂上張望补箍。 院中可真熱鬧,春花似錦啸蜜、人聲如沸坑雅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,996評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽裹粤。三九已至,卻和暖如春蜂林,著一層夾襖步出監(jiān)牢的瞬間遥诉,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,113評論 1 272
  • 我被黑心中介騙來泰國打工悉尾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留突那,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,332評論 3 373
  • 正文 我出身青樓构眯,卻偏偏與公主長得像愕难,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子惫霸,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,044評論 2 355

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