集合框架體系
總體的體系圖:
在學習體系之前先了解一下迭代器(Iterator):迭代器是一種設計模式,它是一個對象,它可以遍歷並選擇序列中的對象,而開發人員不需要了解該序列的底層結構。迭代器通常被稱為“輕量級”對象,因為創建它的代價小。對於集合的輸出,有foreach和iterator,iterator更加的常用。
https://www.cnblogs.com/lxqiaoyixuan/p/7156944.html
其次再了解一下hash和hashcode:
hash函數特性:
調用hashcode()方法計算hash
hash表(散列表):https://www.jianshu.com/p/a89e9487a06c
hash和hashcode:https://blog.csdn.net/m0_37700275/article/details/82800590#commentBox
其次了解一下比較器(在涉及到比較的時候會用到比較器):在很多基本數據類型和引用數據類型中基本上都存在着排序的方法,但是對於自定義的類要實現排序,無法使用系統內部的類(比如Arrays.sort())實現數組排序或者比較需求,是因為沒有提供比較規則,所以提供了一個comparable接口來定義比較規則
comparable:使用需要繼承comparable接口並實現compareto方法,其中compareto方法中如果當前數據比傳入的對象小則返回負數,如果大於那么返回正數,相等則返回0。下面實現一個最基本的比較:
comparator:是一種補救措施,當系統開發完整又需要添加排序功能的時候,但是又不允許修改類的結構(無法實現comparable接口了),這個時候會使用comparator。在挽救中,想要排序的類(這里用Person類)和comparator沒有任何直接關系,關系如圖(PersonComparator是一個排序規則類):
下面來實現一個基本的comparator排序:
首先定義排序規則類:
然后再利用arrays的sort方法傳入排序規則類實現排序:
除非在萬不得已的情況下使用comparator,正常情況下還是使用comparable。
comparable和comparator面試題:請解釋comparator和comparable的區別?
comparable是在類定義的實現的父接口,主要用於定義排序規則,里面只有一個compareto方法。
comparator是挽救的操作,需要設置單獨的比較器規則類實現排序,里面有compare()方法。
最后了解一下二叉樹和紅黑樹:在這之前給出一個數據結構可視化的學習網站:https://www.cs.usfca.edu/~galles/visualization/Algorithms.html
各種樹的結構:https://www.jianshu.com/p/3585745cc45b
二叉樹的遍歷:前,中,后只是指父節點遍歷的順序,前序就是 父節點->左子樹->右子樹,中序是 左子樹->父節點->右子樹,后序是 左子樹 -> 右子樹 ->父節點。
二叉樹的存儲:二叉樹的存儲有兩種存儲方式,順序存儲和鏈式存儲。順序存儲是如圖所示:
極度的浪費空間,如果說空間中的空節點很多的話,會造成空間的極度浪費。
所以還有一種鏈式存儲,又叫二叉鏈表:
二叉樹節點的刪除:分3種情況
https://blog.csdn.net/isea533/article/details/80345507
二叉樹總體學習:https://www.cnblogs.com/skywang12345/p/3576452.html
紅黑樹:紅黑樹的本質就是在節點信息上追加了一個表示顏色的信息而已
特點(不允許紅色節點和紅色節點相連,但是沒有說不允許黑色節點相連):
紅黑樹的自我修正(左旋,右旋,改變節點顏色),插入,刪除操作:https://www.cnblogs.com/ysocean/p/8004211.html ,這篇文章中對於紅黑樹的刪除操作並沒有給出實際的分類情況,而是說刪除太復雜,是通過對刪除的節點做標記來完成刪除操作的。實際上刪除操作分為下面這幾種情況:
需要旋轉的4中情況的分析圖(規則有的時候是聯合使用):
例子:
下面正式開始學習
Collecction(set,list):
Set(hashset,treeset):無序不重復,並不像list那樣擴充了許多新方法,所以無法使用l像ist集合中提供的get方法,所以無法實現指定索引數據的獲取。這是list和set的最大差別。
hashset:無序不重復,當添加重復的元素時,會無效。hashset判斷重復和treeset判斷重復不相同。利用的是object類中的方法進行比較。
首先會利用hashcode進行編碼的匹配,如果編碼不存在,說明不重復。如果編碼存在,那么這個時候進行進一步比較,如果發現重復了,則此數據則不運行保存。在java程序中實現真正的重復元素判斷用的是hashcode和equals兩個方法共同完成的。而只有在排序要求的情況下才會利用comparable接口完成。
treeset:當利用treeset保存的數據的時候所有的數據都按照數據的升序進行自動排序處理。但進行排序的類必須要實現comparable接口,因為只有實現了這個接口才可以比較對象的大小關系。treeset實際上是利用treemap子類實現的集合數據存儲,而treemap(樹)則需要根據comparable來確認大小關系。
注意在使用自定義類進行比較的時候,在繼承comparable后覆寫的方法之中一定要將該類中的所有屬性都依次比較,否則屬性相同的時候會以為是重復數據,所以可以得到得到treeset實際上是通過comparable來確認重復數據的。覆寫的方法如下:
但是如果類中的屬性過多,那么這將是一個很復雜的過程,所以在實際的開發中首選hashset子類。
List:
list和ArrayList:https://www.cnblogs.com/zcscnn/p/7743507.html
基本用法比較:https://blog.csdn.net/ftell/article/details/80826235
深入ArrayList:https://www.cnblogs.com/qingchunshiguang/p/6103731.html
Linkedlist和ArrayList對比:https://blog.csdn.net/weixin_41657730/article/details/82462156
Map(子類有hashmap,treemap,hashtable,linkedhashmap):對於map集合的數據保存格式就是按照“key=value”的形式存儲的,如果key重復,則會出現IllegalArgargumentException(如果是hashmap就會覆蓋)。如果說key為null,那么就是空指針異常。
HashMap(最常見):最常見的map
a.主要特點是無序,tree是有序。
b.在設置了相同的key的內容的時候put方法會返回原始的數據內容,如果沒有相同的key則返回null。
hashmap的原理:https://baijiahao.baidu.com/s?id=1618550070727689060&wfr=spider&for=pc
面試題1:hashmap進行put操作的時候是如何進行容量擴充的?
a.首先會在hashmap中提供一個常量,作為初始化的容量配置,默認大小是16。
b.當保存的容量達到了一個閾值(默認是0.75),這里就是當保存了(16*0.75=12)個元素之后,就會進行容量的擴充。
c.在進行擴充的時候hashmap采用的是成倍的容量擴充,即每一次都擴充2倍(通過對老的容量向左移一位)。
面試題2:請解釋hashmap的工作原理(jdk1.8之后開始,hashmap在jdk1.8之后引入紅黑樹,因為大數據時代的來臨導致數據的爆棚,使得hashmap對數據量的存儲急劇增加,如果說還是使用原本的鏈表存儲大量的數據,會導致效率低下)
a.hashmap中的存儲依然是利用了node類完成,這種情況下的數據結構解釋鏈表和二叉樹(鏈表時間復雜度O(n),二叉樹時復雜度O(logn))。
b.從jdk1.8開始,hashmap的實現發生了改變,因為要適應大數據時代的到來,所以其存儲結構發生了變化,並且在hashmap的內部提供了重要的常量:
,在對hashmap進行數據保存的時候,如果保存的個數沒有超過閾值8,那么會按照鏈表的方式進行存儲,而如果超過了這個閾值,則會把鏈表轉化成紅黑樹以實現樹的平衡,並且利用左旋和右旋保證查找的性能。
面試題3:hashmap的容量為什么是2的n次方?
其中一個主要的方面就是通過hashcode和數組長度通過與運算來計算索引值。詳細見下
https://blog.csdn.net/j1231230/article/details/78072115
紅黑樹產生的問題:為什么使用了紅黑樹還說hashmap是無序的?
因為和treemap不同,treemap是直接將鍵值對中默認按照鍵的升序進行排序。而hashmap首先是按照鍵值轉化成的hashcode存儲在hashmap的數組中,當出現碰撞的時候才存儲在下面的鏈表中,如果說這個時候鏈表過長(超過8個)就會優化為紅黑樹,方便查找的時候更快,所以實際上紅黑樹在hashmap中的作用是為了解決碰撞過多導致的檢索慢的問題。實際在數組中還是無序的,數組查找時間復雜度是O(1)快於treemap,所以如果不用到排序的時候還是使用hashmap效率更高。
hashmap深入理解文章:https://blog.csdn.net/visant/article/details/80045154
Linkedhashmap(有序的hashmap,屬於hashmap的子類,注意這里的有序指的是遍歷順序符合插入順序):https://www.jianshu.com/p/8f4f58b4b8ab
Hashtable(最早的一批動態數組實現類,很少使用了):hashtable在進行數據存儲的時候,如果key或者value為空都會出現空指針異常。
ConcurrentHashMap(hashtable的替代者,線程安全,分段):
jdk1.7下的concurrenthashmap:
在jdk1.7和1.8的實現不相同,jdk7中采用的是分段的數組加鏈表實現,1.7中的存儲結構如下:
面試細節:https://www.cnblogs.com/heyonggang/p/9112731.html
jdk8下的concurrenthashmap(采用CAS + synchronized):
a.將Segment拋棄掉了,直接采用Node(繼承自Map.Entry)作為table元素。
b.修改時,不再采用ReentrantLock加鎖,直接用內置synchronized加鎖,java8的內置鎖比之前版本優化了很多,相較ReentrantLock,性能不並差。
c.size方法優化,增加了CounterCell內部類,用於並行計算每個bucket的元素數量。

面試題:請解釋hashmap的hashtable的區別?
hashmap中的方法屬於異步操作,非線程安全,hashmap允許保存有空數據。
hashtable中的方法都屬於同步方法,線程安全,hashtable不允許保存空數據,否則出現空指針異常。
TreeMap:底層通過紅黑樹實現
幾種map的對比: