剛開始學,稀裏糊塗的寫一點。。。
ArrayList
參考博客:https://www.cnblogs.com/leesf456/p/5308358.html
1、ArrayList底層的數據結構其實就是一個可變數組,數組的元素類型是Object類型,可以存放各種類型的數據,允許null的存在。
2、ArrayList繼承了AbstractList抽象父類,實現了List接口(規定了List的操作規範)、RandomAccess(可隨機訪問)、 Cloneable(可拷貝)、Serializable(可序列化)。
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable
3、數組默認大小爲10,實際元素個數默認爲0。
4、當實際元素個數達到容量大小時,會進行擴容,擴容後的數組大小大約爲舊數組大小的1.5倍。特殊情況:擴展的新數組大小達到最大值,則只能取最大值。
5、remove函數,會把下標到末尾的元素都向前移動一位,並把最後一個位置置爲null,這樣做是爲了方便GC。
6、採用了Fail-Fast(快速失敗)機制,面對併發的修改時,迭代器很快就會完全失敗。
LinkedList
參考博客:https://www.cnblogs.com/leesf456/p/5308843.html
1、LinkedList底層的數據結構是雙向鏈表,並且有一個頭節點和一個尾節點,這樣既可以從頭正向遍歷,也可以從尾逆向遍歷。允許null的存在。
2、雙向鏈表節點是類Node的實例,包含的成員變量:prev,next,item。prev是該節點的上一個節點,next是該節點的下一個節點,item是該節點的值。
3、get函數和addall函數都會用到node函數,node函數的作用是根據索引下標找到該結點並返回。在node函數裏面有一個小的優化,首先會判斷下標在前半部分還是在後半部分,在前半部分時就正向遍歷,否則逆向遍歷,這樣就保證了最多遍歷n/2個元素,節省了時間。
HashMap
參考博客:東拼西湊的看的。。。
1、HashMap底層是數組+鏈表+紅黑樹(紅黑樹還有待學習)實現的,數組中的每一項都是一個單向鏈表,允許使用null鍵和null值,但不保證映射的順序。
2、數組默認大小是16,加載因子默認大小是0.75,也可以自行設定容量以及加載因子,當放入的鍵值對數量超過容量乘以加載因子(即閾值)的時候,就會進行擴容。
3、當對key進行hash時,如果有hash值相等的,那麼就會形成一個鏈表,如果鏈表的長度超過了8,那麼就會轉化成紅黑樹,不轉化會降低查詢效率。
4、採用了Fail-Fast機制,通過一個modCount值記錄修改次數,對HashMap內容的修改都將增加這個值。迭代器初始化過程中會將這個值賦給迭代器的expectedModCount,在迭代過程中,判斷modCount跟expectedModCount是否相等,如果不相等就表示已經有其他線程修改了Map,馬上拋出異常。
HashTable
參考博客:https://blog.csdn.net/varyall/article/details/80992123
1、採用Fail-Fast機制。
2、HashTable的底層是數組+鏈表實現的,不允許使用null鍵和null值。
3、默認數組容量爲11,加載因子爲0.75,也可以自行設定。
4、與HashMap實現差不多,且沒有紅黑樹的引入。
5、擴容時,新數組的長度爲舊數組長度 * 2 + 1。
Hash Map與Hash Table的區別
1、HashMap可以允許存在一個爲null的key和任意個爲null的value,但是HashTable中的key和value都不允許爲null。
2、Hashtable的方法是同步的,而HashMap的方法不是。所以有人一般都建議如果是涉及到多線程同步時採用HashTable,沒有涉及就採用HashMap。
3、兩個遍歷方式的內部實現上不同。Hashtable、HashMap都使用了 Iterator。而由於歷史原因,Hashtable還使用了Enumeration的方式 。
4、計算hash值的不同。HashTable通過hashCode方法計算得到的hash值,就爲最終的hash值;而HashMap是先通過hashCode方法計算得到一個hash值,然後再將這個hash值與右移16位之後異或,得到最終的hash值。
5、HashTable默認數組長度爲11,擴容後新數組長度 = 舊數組長度 * 2 + 1;HashMap默認數組長度爲16,擴容後新數組長度 = 舊數組長度 * 2。