日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

JAVA集合源码

發布時間:2023/12/10 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 JAVA集合源码 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄
JAVA集合
一、框架圖
二、List
1.ArrayList(部分源碼)
2.LinkedList(部分源碼)
3.Vector(部分源碼)
三、Set
1.HashSet(部分源碼)
2.LinkedHashSet(部分源碼)
3.TreeSet(部分源碼)
四、Queue
1.LinkedList(用作隊列或棧的部分源碼)
2.ArrayDeque(部分源碼)
五、Map
1.HashMap(部分源碼)
2.LinkedHashMap(部分源碼)
3.TreeMap(部分源碼)
4.Hashtable(部分源碼)
總結
JAVA集合
所有集合類都位于java.util包下,支持多線程的集合類位于java.util.concurrent包下。所有的集合框架都包括接口、實現類、算法。實現類就是具體數據結構的實現

一、框架圖

Java集合類主要的兩個根接口,Collection和Map
Collection又派生出List、Set、Queue(Java5新增的隊列)三個子接口
List接口下的常見實現類有ArrayList、LinkedList、Vector
Queue接口下的常見實現類有ArrayDeque、LinkedList
Set接口下的常見實現類有HashSet、LinkedHashSet、SortedSet、TreeSet
Map接口下的常見實現類有HashMap、LinkedHashMap、HashTable、Properties、SortedMap、TreeMap
下面說一下常用常見的實現類(所有源碼均參照JDK11)

二、List
List元素按插入順序,可插入重復元素,能夠通過索引訪問元素

1.ArrayList(部分源碼)
基本屬性

?? ?private static final int DEFAULT_CAPACITY = 10;//默認初始空間
? ? private static final Object[] EMPTY_ELEMENTDATA = {};//空數組
? ? private int size;//ArrayList中的元素個數
?? ?private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//空數組
?? ?transient Object[] elementData; //ArrayList的本質就是該數組
?? ?private int size;//數組中元素數
1
2
3
4
5
6
構造器

?? ?//指定初始容量
?? ?public ArrayList(int initialCapacity) {
? ? ? ? if (initialCapacity > 0) {//指定初始容量大于0
? ? ? ? ? ? this.elementData = new Object[initialCapacity];//創建指定容量數組數組
? ? ? ? } else if (initialCapacity == 0) {//等于構建空數組
? ? ? ? ? ? this.elementData = EMPTY_ELEMENTDATA;
? ? ? ? } else {//小于0拋出異常
? ? ? ? ? ? throw new IllegalArgumentException("Illegal Capacity: "+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);
? ? ? ? }
? ? }
? ? //默認創建一個空數組
?? ?public ArrayList() {
?? ? ? ?this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
?? ?}
?? ?//將集合轉為ArrayList
?? ?public ArrayList(Collection<? extends E> c) {
? ? ? ? elementData = c.toArray();//其他集合中的實現方法
? ? ? ? if ((size = elementData.length) != 0) {//要轉換的集合中元素個數不為0
? ? ? ? ? ? if (elementData.getClass() != Object[].class)//當集合中元素不是Object類型時,轉為Object
? ? ? ? ? ? ? ? elementData = Arrays.copyOf(elementData, size, Object[].class);
? ? ? ? } else {//集合中不存在元素,創建空數組
? ? ? ? ? ? this.elementData = EMPTY_ELEMENTDATA;
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
添加元素

?? ?//在尾部添加元素
? ? public boolean add(E e) {
? ? ? ? modCount++;
? ? ? ? add(e, elementData, size);
? ? ? ? return true;
? ? }
? ? /**
? ? ?* 添加元素的實際操作
? ? ?* JDK的注釋是說將這個方法單獨分離出來,是為了將方法字節碼保持在35以下,
? ? ?* 在C1編譯循環中會有幫助,這個倒沒研究過
? ? ?*/
? ? private void add(E e, Object[] elementData, int s) {
? ? ? ? if (s == elementData.length)//當元素個數等于數組大小,需要擴容
? ? ? ? ? ? elementData = grow();
? ? ? ? elementData[s] = e;//插入元素到數組
? ? ? ? size = s + 1;//元素個數統計
? ? }
?? ?private Object[] grow() {
? ? ? ? return grow(size + 1);
? ? }
?? ?//具體的擴容操作
? ? private Object[] grow(int minCapacity) {
? ? ?? ?//計算新的空間大小,復制數組以達到擴容
? ? ? ? return elementData = Arrays.copyOf(elementData,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?newCapacity(minCapacity));
? ? }
?? ?//計算新空間大小
? ? private int newCapacity(int minCapacity) {
? ? ? ? int oldCapacity = elementData.length;//當前的數組的長度
? ? ? ? int newCapacity = oldCapacity + (oldCapacity >> 1);//新數組的長度,按目標數組長度的右位運算進行擴容(s+ (int)s/2)
? ? ? ? if (newCapacity - minCapacity <= 0) {//擴容后的容量小于等于數組最小容量
? ? ? ? ? ? if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)//如果當前數組是空數組
? ? ? ? ? ? ? ? return Math.max(DEFAULT_CAPACITY, minCapacity);//返回默認初始容量和數組最小容量中的的最大值
? ? ? ? ? ? if (minCapacity < 0) //所需最小容量小于0,拋出異常
? ? ? ? ? ? ? ? throw new OutOfMemoryError();
? ? ? ? ? ? return minCapacity;//返回所需最小容量
? ? ? ? }
? ? ? ? //防止分配空間超過最大分配空間
? ? ? ? return (newCapacity - MAX_ARRAY_SIZE <= 0)
? ? ? ? ? ? ? newCapacity
? ? ? ? ? ? : hugeCapacity(minCapacity);
? ? }
?? ?//當分配空間超過可分配最大空間
?? ?private static int hugeCapacity(int minCapacity) {
? ? ? ? if (minCapacity < 0) // overflow
? ? ? ? ? ? throw new OutOfMemoryError();
? ? ? ? //所需最小空間大于可分配最大空間,返回int最大值,所需最小空間小于可分配的最大空間就返回最大可分配空間
? ? ? ? return (minCapacity > MAX_ARRAY_SIZE)
? ? ? ? ? ? ? Integer.MAX_VALUE
? ? ? ? ? ? : MAX_ARRAY_SIZE;
? ? }
? ??
?? ?//在指定位置插入元素
? ? public void add(int index, E element) {
? ? ?? ?//檢查指定位置是否在集合長度內
? ? ? ? rangeCheckForAdd(index);
? ? ? ? modCount++;
? ? ? ? final int s;
? ? ? ? Object[] elementData;
? ? ? ? if ((s = size) == (elementData = this.elementData).length)
? ? ? ? ?? ?//元素個數等于數組大小時,擴容
? ? ? ? ? ? elementData = grow();
? ? ? ? System.arraycopy(elementData, index,
? ? ? ? ? ? ? ? ? ? ? ? ?elementData, index + 1,
? ? ? ? ? ? ? ? ? ? ? ? ?s - index);
? ? ? ? elementData[index] = element;
? ? ? ? size = s + 1;
? ? }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
刪除元素

?? ?//刪除指定位置元素
?? ?public E remove(int index) {
? ? ? ? Objects.checkIndex(index, size);//檢查指定位置是否在數組長度內
? ? ? ? final Object[] es = elementData;
? ? ? ? @SuppressWarnings("unchecked") E oldValue = (E) es[index];//要刪除的元素
? ? ? ? fastRemove(es, index);//將刪除的元素后面的元素全部左移一位
? ? ? ? return oldValue;
? ? }
? ? //遍歷數組找到該元素第一次出現的位置,將后面的元素全部左移
? ? public boolean remove(Object o) {
? ? ? ? final Object[] es = elementData;
? ? ? ? final int size = this.size;
? ? ? ? int i = 0;
? ? ? ? found: {
? ? ? ? ? ? if (o == null) {//指定元素是null
? ? ? ? ? ? ? ? for (; i < size; i++)
? ? ? ? ? ? ? ? ? ? if (es[i] == null)//第一次出現該元素的位置
? ? ? ? ? ? ? ? ? ? ? ? break found;
? ? ? ? ? ? } else {//指定元素不是null
? ? ? ? ? ? ? ? for (; i < size; i++)
? ? ? ? ? ? ? ? ? ? if (o.equals(es[i]))//第一次出現該元素的位置
? ? ? ? ? ? ? ? ? ? ? ? break found;
? ? ? ? ? ? }
? ? ? ? ? ? return false;//不存在該元素返回false
? ? ? ? }
? ? ? ? fastRemove(es, i);//將刪除的元素后面的元素全部左移一位
? ? ? ? return true;
? ? }
? ? private void fastRemove(Object[] es, int i) {
? ? ? ? modCount++;
? ? ? ? final int newSize;//刪除元素后的數組長度
? ? ? ? if ((newSize = size - 1) > i)//刪除元素不是最后一個元素
? ? ? ? ?? ?//將原數組指定位置開始的元素,復制到原數組,從原數組的要刪除元素的位置開始覆蓋,相當于要刪除元素后面的所有元素全部左移一位
? ? ? ? ? ? System.arraycopy(es, i + 1, es, i, newSize - i);
? ? ? ? es[size = newSize] = null;//刪除元素是最后一個元素,將數組元素數量減一,然后清空該位置元素
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ArrayList底層是基于數組實現,默認初始容量是10,擴容大小大約1.5倍,可以直接通過下標取得元素,增加和刪除元素都需要新創建數組效率較低,可以指定初始容量值,避免過多的進行擴容操作

2.LinkedList(部分源碼)
基本屬性

?? ?//鏈表長度(元素個數)
?? ?transient int size = 0;
? ? //指向第一個節點的指針
? ? transient Node<E> first;
? ? //指向最后一個節點的指針
? ? transient Node<E> last;
?? ?//節點結構
?? ?private static class Node<E> {
?? ??? ?//自身
? ? ? ? E item;
? ? ? ? //下一個節點
? ? ? ? Node<E> next;
? ? ? ? //上一個節點
? ? ? ? Node<E> prev;
? ? ? ? Node(Node<E> prev, E element, Node<E> next) {
? ? ? ? ? ? this.item = element;
? ? ? ? ? ? this.next = next;
? ? ? ? ? ? this.prev = prev;
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
構造器

?? ?//創建一個空LinkedList
?? ?public LinkedList() {}
?? ?//構建包含指定元素的列表
?? ?public LinkedList(Collection<? extends E> c) {
? ? ? ? this();
? ? ? ? addAll(c);
? ? }
? ? public boolean addAll(Collection<? extends E> c) {
? ? ? ? return addAll(size, c);
? ? }
? ? //將指定集合中的元素加入列表中
? ? public boolean addAll(int index, Collection<? extends E> c) {
? ? ? ? checkPositionIndex(index);
? ? ? ? Object[] a = c.toArray();//轉為數組
? ? ? ? int numNew = a.length;//長度(元素個數)
? ? ? ? if (numNew == 0)//不存在元素,返回false
? ? ? ? ? ? return false;

? ? ? ? Node<E> pred, succ;//插入節點的前驅和后繼節點
? ? ? ? if (index == size) {//從尾部開始插入的情況
? ? ? ? ? ? succ = null;//后繼節點為null
? ? ? ? ? ? pred = last;//前驅節點是原來的尾部節點
? ? ? ? } else {//從指定位置開始插入(非尾部)
? ? ? ? ? ? succ = node(index);//獲取index位置的節點,用作插入節點的后繼節點
? ? ? ? ? ? pred = succ.prev;//index位置的節點的前驅節點,用作插入節點的前驅節點
? ? ? ? }
? ? ? ? for (Object o : a) {//遍歷數組元素,插入到鏈表
? ? ? ? ? ? @SuppressWarnings("unchecked") E e = (E) o;
? ? ? ? ? ? Node<E> newNode = new Node<>(pred, e, null);//創建節點
? ? ? ? ? ? if (pred == null)//前驅是null,表示是從頭部開始插入,或者鏈表是null
? ? ? ? ? ? ? ? first = newNode;//新節點用作頭部節點
? ? ? ? ? ? else
? ? ? ? ? ? ? ? pred.next = newNode;//前驅后繼指向新節點
? ? ? ? ? ? pred = newNode;//記錄前驅節點為最新插入的節點
? ? ? ? }

? ? ? ? if (succ == null) {//從尾部開始插入
? ? ? ? ? ? last = pred;//將尾部節點置為最后一個插入節點
? ? ? ? } else {//指定位置開始插入(非尾部)
? ? ? ? ? ? pred.next = succ;//插入的最后一個節點的后繼節點置為原本index位置節點的后繼節點
? ? ? ? ? ? succ.prev = pred;//原本index位置的后繼節點的前驅節點置為插入的最后一個節點
? ? ? ? }

? ? ? ? size += numNew;//鏈表長度
? ? ? ? modCount++;//修改次數加1
? ? ? ? return true;
? ? }
? ? Node<E> node(int index) {
? ? ? ? if (index < (size >> 1)) {//右運算,判斷index位置在linkedlist的前半段,從頭部開始迭代
? ? ? ? ? ? Node<E> x = first;
? ? ? ? ? ? for (int i = 0; i < index; i++)//找到并返回在index位置的節點
? ? ? ? ? ? ? ? x = x.next;
? ? ? ? ? ? return x;
? ? ? ? } else {//判斷index位置在linkedlist的后半段,從尾部開始迭代
? ? ? ? ? ? Node<E> x = last;
? ? ? ? ? ? for (int i = size - 1; i > index; i--)//找到并返回在index位置的節點
? ? ? ? ? ? ? ? x = x.prev;
? ? ? ? ? ? return x;
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
添加元素

?? ?//將元素添加到列表末尾
?? ?public boolean add(E e) {
? ? ? ? linkLast(e);
? ? ? ? return true;
? ? }
?? ?//將指定元素添加到鏈表尾部
? ? void linkLast(E e) {
? ? ? ? final Node<E> l = last;//原本的尾部節點
? ? ? ? final Node<E> newNode = new Node<>(l, e, null);//新節點
? ? ? ? last = newNode;//尾部節點置為新節點
? ? ? ? if (l == null)//原本的尾部節點是null,鏈表是空,頭結點和尾部節點指向同一節點
? ? ? ? ? ? first = newNode;//頭結點置為新節點
? ? ? ? else
? ? ? ? ? ? l.next = newNode;//原本尾部節點的后繼置為新尾部節點
? ? ? ? size++;//元素加1
? ? ? ? modCount++;//修改次數加1
? ? }
? ? //將元素添加到列表開頭
?? ?public void addFirst(E e) {
? ? ? ? linkFirst(e);
? ? }
? ? //將指定元素插入到頭部
? ? private void linkFirst(E e) {
? ? ? ? final Node<E> f = first;//原本頭節點
? ? ? ? final Node<E> newNode = new Node<>(null, e, f);//新節點(新頭部節點)
? ? ? ? first = newNode;//頭部節點置為新節點
? ? ? ? if (f == null)//原本頭結點是null,鏈表為空,頭節點指針和尾節點指針指向同一節點
? ? ? ? ? ? last = newNode;
? ? ? ? else
? ? ? ? ? ? f.prev = newNode;//將原本頭節點的前驅節點置為新節點
? ? ? ? size++;
? ? ? ? modCount++;
? ? }
? ? //和add方法一樣只是無返回值,(尾部插入元素)
?? ?public void addLast(E e) {
? ? ? ? linkLast(e);
? ? } ? ? ?
? ? //在指點位置插入元素
? ? public void add(int index, E element) {
? ? ? ? checkPositionIndex(index);//檢查指定位置是否在列表長度內
? ? ? ? if (index == size)//指定位置等于鏈表長度,直接插入尾部?
? ? ? ? ? ? linkLast(element);
? ? ? ? else
? ? ? ? ? ? linkBefore(element, node(index));//指定位置插入元素,node(index)表示獲取index位置的節點,參考構造器
? ? }
? ? //指定位置插入元素
? ? void linkBefore(E e, Node<E> succ) {
? ? ? ? final Node<E> pred = succ.prev;//原本index位置的前驅節點,用作新節點的前驅節點
? ? ? ? final Node<E> newNode = new Node<>(pred, e, succ);//新節點,后繼節點為原本index位置的后繼節點
? ? ? ? succ.prev = newNode;//原本index位置節點的前驅節點置為新節點
? ? ? ? if (pred == null)//原本index位置的前驅節點是null,插入到頭部
? ? ? ? ? ? first = newNode;//頭部節點指針置為新節點
? ? ? ? else
? ? ? ? ? ? pred.next = newNode;//原本index 位置節點的前驅節點的后繼節點置為新節點
? ? ? ? size++;
? ? ? ? modCount++;
? ? }
? ??
?? ?//壓棧,鏈表頭部看做棧頂,只在頭部一端做操作
?? ?public void push(E e) {
? ? ? ? addFirst(e);
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
刪除元素

?? ?//根據指定位置刪除元素
?? ?public E remove(int index) {
? ? ? ? checkElementIndex(index);
? ? ? ? return unlink(node(index));//先獲取指定位置的節點
? ? }
? ? //刪除指定節點
? ? E unlink(Node<E> x) {
? ? ? ? final E element = x.item;//要刪除的元素
? ? ? ? final Node<E> next = x.next;//要刪除節點的后繼節點
? ? ? ? final Node<E> prev = x.prev;//要刪除節點的前驅節點
? ? ? ? if (prev == null) {//前驅節點是null,要刪除的是頭部節點
? ? ? ? ? ? first = next;//頭部節點置為后繼節點
? ? ? ? } else {
? ? ? ? ? ? prev.next = next;//要刪除節點的前驅節點的后繼節點置為要刪除節點的后繼節點
? ? ? ? ? ? x.prev = null;//清空要刪除節點的前驅節點指向
? ? ? ? }
? ? ? ? if (next == null) {//后繼節點是null,要刪除的節點是尾部節點
? ? ? ? ? ? last = prev;//將要刪除節點的前驅節點置為尾部節點
? ? ? ? } else {
? ? ? ? ? ? next.prev = prev;//要刪除節點的后繼節點的前驅節點置為要刪除節點的前驅節點
? ? ? ? ? ? x.next = null;//要刪除節點的后繼節點指向清空
? ? ? ? }
? ? ? ? x.item = null;//要刪除節點的本身元素清空
? ? ? ? size--;
? ? ? ? modCount++;
? ? ? ? return element;//返回刪除的元素
? ? }
? ??
? ? //刪除列表中指定元素(只刪除第一個出現的該元素)
? ? public boolean remove(Object o) {
? ? ? ? if (o == null) {//指定元素是null
? ? ? ? ? ? for (Node<E> x = first; x != null; x = x.next) {//迭代
? ? ? ? ? ? ? ? if (x.item == null) {//找到第一個出現指定元素的節點
? ? ? ? ? ? ? ? ? ? unlink(x);//刪除節點
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? for (Node<E> x = first; x != null; x = x.next) {
? ? ? ? ? ? ? ? if (o.equals(x.item)) {
? ? ? ? ? ? ? ? ? ? unlink(x);
? ? ? ? ? ? ? ? ? ? return true;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return false;
? ? }
? ??
?? ?//彈棧
?? ?public E pop() {
? ? ? ? return removeFirst();//移除棧頂元素
? ? }
? ? public E removeFirst() {
? ? ? ? final Node<E> f = first;//頭部節點
? ? ? ? if (f == null)//頭部節點是null,鏈表為空,拋出異常
? ? ? ? ? ? throw new NoSuchElementException();
? ? ? ? return unlinkFirst(f);
? ? }
? ? //移除頭部節點
? ? private E unlinkFirst(Node<E> f) {
? ? ? ? // assert f == first && f != null;
? ? ? ? final E element = f.item;//要移除元素
? ? ? ? final Node<E> next = f.next;//后繼節點
? ? ? ? f.item = null;//移除節點的元素置為null
? ? ? ? f.next = null; //移除節點的后繼節點置為null ? (方便GC)
? ? ? ? first = next;//將后繼節點置為新的頭部節點
? ? ? ? if (next == null)//更新后繼節點的前驅指向:后繼節點是null,刪除的同時也是尾部節點(只存在一個節點)
? ? ? ? ? ? last = null;//尾部節點置為null
? ? ? ? else
? ? ? ? ? ? next.prev = null;//后繼節點置為了新的頭部節點,前驅指向置為null
? ? ? ? size--;
? ? ? ? modCount++;
? ? ? ? return element;//返回刪除的元素
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
獲取元素

?? ?//返回列表中第一個出現的該元素的索引
?? ?public int indexOf(Object o) {
? ? ? ? int index = 0;//索引
? ? ? ? if (o == null) {//指定元素是null
? ? ? ? ? ? for (Node<E> x = first; x != null; x = x.next) {//從頭部開始迭代
? ? ? ? ? ? ? ? if (x.item == null)//找到第一個出現的指定元素
? ? ? ? ? ? ? ? ? ? return index;//返回索引
? ? ? ? ? ? ? ? index++;//記錄索引
? ? ? ? ? ? }
? ? ? ? } else {
? ? ? ? ? ? for (Node<E> x = first; x != null; x = x.next) {
? ? ? ? ? ? ? ? if (o.equals(x.item))
? ? ? ? ? ? ? ? ? ? return index;
? ? ? ? ? ? ? ? index++;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return -1;//沒找到返回-1
? ? }
? ? //獲取指定位置元素
? ? public E get(int index) {
? ? ? ? checkElementIndex(index);
? ? ? ? return node(index).item;
? ? }

?? ?//獲取棧頂元素
?? ?public E peek() {
? ? ? ? final Node<E> f = first;//頭部元素
? ? ? ? return (f == null) ? null : f.item;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
LinkedList底層基于雙向鏈表實現,同時實現了Deque接口,可以當做雙向隊列使用,也可以當做棧使用,當做棧使用的時候是封住了鏈表尾部只在鏈表頭部進行插入和刪除操作;查找元素需要迭代列表效率較低,在插入和刪除上有較好的性能

3.Vector(部分源碼)
基本屬性

?? ?protected Object[] elementData;//存儲元素的數組
?? ?protected int elementCount;//實際的元素個數
?? ?protected int capacityIncrement;//容量增長系數,小于或等于0將會成倍增長
1
2
3
構造器

?? ?//指定初始容量和需要自動擴容時增加的容量
?? ?public Vector(int initialCapacity, int capacityIncrement) {
? ? ? ? super();
? ? ? ? if (initialCapacity < 0)//初始容量小于0拋出異常
? ? ? ? ? ? throw new IllegalArgumentException("Illegal Capacity: "+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);
? ? ? ? this.elementData = new Object[initialCapacity];//創建指定容量的數組
? ? ? ? this.capacityIncrement = capacityIncrement;
? ? }
?? ?public Vector(int initialCapacity) {
? ? ? ? this(initialCapacity, 0);
? ? }
?? ?//默認初始容量10
? ? public Vector() {
? ? ? ? this(10);
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
添加元素

?? ?//在數組末尾插入元素
?? ?public synchronized boolean add(E e) {
? ? ? ? modCount++;
? ? ? ? add(e, elementData, elementCount);
? ? ? ? return true;
? ? }
? ? private void add(E e, Object[] elementData, int s) {
? ? ? ? if (s == elementData.length)//數組容量到達上限需要擴容
? ? ? ? ? ? elementData = grow();
? ? ? ? elementData[s] = e;//插入元素到數組
? ? ? ? elementCount = s + 1;//元素個數加1
? ? }
? ? private Object[] grow() {
? ? ? ? return grow(elementCount + 1);//數組當前實際元素個數加1,表示數組所需最小容量
? ? }
? ? private Object[] grow(int minCapacity) {
? ? ? ? return elementData = Arrays.copyOf(elementData,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?newCapacity(minCapacity));
? ? }
? ? //計算新空間
? ? private int newCapacity(int minCapacity) {
? ? ? ? int oldCapacity = elementData.length;//數組當前長度
? ? ? ? //計算新長度,capacityIncrement大于0就按capacityIncrement擴容,否則當前長度翻一倍
? ? ? ? int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?capacityIncrement : oldCapacity);
? ? ? ? if (newCapacity - minCapacity <= 0) {//新空間要小于等于所需最小空間
? ? ? ? ? ? if (minCapacity < 0) //所需最小空間驗證
? ? ? ? ? ? ? ? throw new OutOfMemoryError();
? ? ? ? ? ? return minCapacity;//返回最小空間作為新空間大小
? ? ? ? }
? ? ? ? return (newCapacity - MAX_ARRAY_SIZE <= 0)//當新空間大小超過可分配最大空間的處理
? ? ? ? ? ? ? newCapacity
? ? ? ? ? ? : hugeCapacity(minCapacity);
? ? }
? ? //當新空間大小超過可分配最大空間的處理
? ? private static int hugeCapacity(int minCapacity) {
? ? ? ? if (minCapacity < 0)
? ? ? ? ? ? throw new OutOfMemoryError();
? ? ? ? return (minCapacity > MAX_ARRAY_SIZE) ?//所需最小空間要大于可分配最大空間,使用整形最大值,否則使用可分配最大空間
? ? ? ? ? ? Integer.MAX_VALUE :
? ? ? ? ? ? MAX_ARRAY_SIZE;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
刪除元素

? ? //移除指定位置元素
? ? public synchronized E remove(int index) {
? ? ? ? modCount++;
? ? ? ? if (index >= elementCount)
? ? ? ? ? ? throw new ArrayIndexOutOfBoundsException(index);
? ? ? ? E oldValue = elementData(index);//獲取指定位置元素
? ? ? ? int numMoved = elementCount - index - 1;//需要移動的元素數量
? ? ? ? if (numMoved > 0)//大于0表示不是末尾元素
? ? ? ? ? ? System.arraycopy(elementData, index+1, elementData, index,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?numMoved);//將指定位置后面的元素全部左移一位
? ? ? ? elementData[--elementCount] = null;// Let gc do its work
? ? ? ? return oldValue;//返回移除的元素
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
Vector和ArrayList相似,底層也是基于數組實現,不同的是Vector默認初始容量是10,沒有指定擴容系數的話是翻一倍擴容,并且Vector是線程安全的,可以看到在插入元素和刪除元素的方法有使用sychronized關鍵字

三、Set
Set元素插入無序,不能保存重復元素

1.HashSet(部分源碼)
?? ?private transient HashMap<E,Object> map;
? ? private static final Object PRESENT = new Object();//鍵值對用作value的虛擬值
?? ?public HashSet() {
? ? ? ? map = new HashMap<>();
? ? }
? ? public HashSet(int initialCapacity, float loadFactor) {
? ? ? ? map = new HashMap<>(initialCapacity, loadFactor);
? ? }
? ? public HashSet(int initialCapacity) {
? ? ? ? map = new HashMap<>(initialCapacity);
? ? }
? ? HashSet(int initialCapacity, float loadFactor, boolean dummy) {//這個構造器是為LinkedHashSet提供的支持
? ? ? ? map = new LinkedHashMap<>(initialCapacity, loadFactor);
? ? }
? ? public boolean add(E e) {
? ? ? ? return map.put(e, PRESENT)==null;
? ? }
? ? public boolean remove(Object o) {
? ? ? ? return map.remove(o)==PRESENT;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
可以看出HashSet的底層就是采用的HashMap來實現的,并且所有提供的方法內部都是通過HashMap操作完成的,可以直接參考HashMap

2.LinkedHashSet(部分源碼)
?? ?public LinkedHashSet(int initialCapacity, float loadFactor) {
? ? ? ? super(initialCapacity, loadFactor, true);
? ? }
? ? public LinkedHashSet(int initialCapacity) {
? ? ? ? super(initialCapacity, .75f, true);
? ? }
? ? public LinkedHashSet() {
? ? ? ? super(16, .75f, true);
? ? }
1
2
3
4
5
6
7
8
9
LinkedHashSet是HashSet子類的底層就是采用的LinkedHashMap來實現的,LinkedHashMap又是HashMap的子類,可以直接參考HashMap和LinkedHashMap

3.TreeSet(部分源碼)
?? ?/**
? ? ?* The backing map.
? ? ?*/
? ? private transient NavigableMap<E,Object> m;
? ? private static final Object PRESENT = new Object();//鍵值對用作value的虛擬值
? ? TreeSet(NavigableMap<E,Object> m) {//該方式TreeSet初始化時 底層是map
? ? ? ? this.m = m;
? ? }
? ? public TreeSet() {
? ? ? ? this(new TreeMap<>());
? ? }
? ? public TreeSet(Comparator<? super E> comparator) {
? ? ? ? this(new TreeMap<>(comparator));
? ? }
? ? public boolean add(E e) {
? ? ? ? return m.put(e, PRESENT)==null;
? ? }
? ? public boolean remove(Object o) {
? ? ? ? return m.remove(o)==PRESENT;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
TreeSet底層是基于TreeMap作為容器來實現的,參考TreeMap

四、Queue
Queue代表隊列,是一種特殊的線性表,隊列中只允許在表的前端出隊,后端入隊,又被叫做先進先出(FIFO)線性表;子接口Deque是雙向隊列的實現,雙向隊列是表雙端都可以進行出隊入隊操作,棧是一種后進先出的數據結構,只要將雙向隊列的一端封住那么就可以當做棧來使用了。Deque的實現類有LinkedList和ArrayDeque

1.LinkedList(用作隊列或棧的部分源碼)
?? ?//彈棧
?? ?public E pop() {
? ? ? ? return removeFirst();
? ? }
? ? //壓棧
? ? public void push(E e) {
? ? ? ? addFirst(e);
? ? }
? ?? ?//獲取棧頂元素 ?
? ? public E peek() {
? ? ? ? final Node<E> f = first;
? ? ? ? return (f == null) ? null : f.item;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
2.ArrayDeque(部分源碼)
?? ?transient Object[] elements;
?? ?//默認初始容量16
?? ?public ArrayDeque() {
? ? ? ? elements = new Object[16];
? ? }
?? ?//在Deque末尾插入指定元素
?? ?public boolean add(E e) {
? ? ? ? addLast(e);
? ? ? ? return true;
? ? }
? ? public void addLast(E e) {
? ? ? ? if (e == null)
? ? ? ? ? ? throw new NullPointerException();
? ? ? ? final Object[] es = elements;
? ? ? ? es[tail] = e;
? ? ? ? if (head == (tail = inc(tail, es.length)))
? ? ? ? ? ? grow(1);
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
ArrayDeque底層基于數組實現,默認初始容量是16,添加刪除元素和ArrayList有很多相似的地方,可以參考ArrayList,用作隊列或棧的時候,肯定會過多的涉及元素的出棧入棧,更推薦使用LinkedList效率更高,ArrayDeque就沒有著重去看

五、Map
Map接口采用鍵值對具有映射關系的形式存儲數據,可以存儲null,添加元素key存在時會覆蓋value,所有key不能重復,但是value可以重復

1.HashMap(部分源碼)
?? ?//默認初始容量
? ? static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
? ? //最大容量
?? ?static final int MAXIMUM_CAPACITY = 1 << 30;
?? ?//默認的負載因子
?? ?static final float DEFAULT_LOAD_FACTOR = 0.75f;
?? ?//當桶節點數量大于8就會轉為紅黑樹(JDK1.8引入的紅黑樹)
?? ?static final int TREEIFY_THRESHOLD = 8;
?? ?//當桶節點數量小于6就會轉為鏈表,前提條件是當前桶是紅黑樹結構
?? ?static final int UNTREEIFY_THRESHOLD = 6;
?? ?//當HashMap中的所有元素數量大于64,也會轉為紅黑樹
?? ?static final int MIN_TREEIFY_CAPACITY = 64;

?? ?//節點內部類,將一個鍵值對對象化
?? ?static class Node<K,V> implements Map.Entry<K,V> {
? ? ? ? final int hash;//哈希值
? ? ? ? final K key;
? ? ? ? V value;
? ? ? ? Node<K,V> next;

? ? ? ? Node(int hash, K key, V value, Node<K,V> next) {
? ? ? ? ? ? this.hash = hash;
? ? ? ? ? ? this.key = key;
? ? ? ? ? ? this.value = value;
? ? ? ? ? ? this.next = next;
? ? ? ? }
?? ??? ?
? ? ? ? public final int hashCode() {
? ? ? ? ? ? return Objects.hashCode(key) ^ Objects.hashCode(value);
? ? ? ? }
? ? }
?? ?//哈希桶,存放鍵值對元素的數組
?? ?transient Node<K,V>[] table;
?? ?//存放具體元素的集
?? ?transient Set<Map.Entry<K,V>> entrySet;
?? ?//閾值,元素數量超過閾值發生擴容
?? ?int threshold;
?? ?//哈希表的加載因子
?? ?final float loadFactor;
?? ?//紅黑樹
?? ?static final class TreeNode<K, V> extends LinkedHashMap.Entry<K, V> {
? ? ? ? TreeNode<K, V> parent;
? ? ? ? TreeNode<K, V> left;
? ? ? ? TreeNode<K, V> right;
? ? ? ? TreeNode<K, V> prev;
? ? ? ? boolean red;
?
? ? .......
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
上面是HashMap的一些基本屬性,可以看出底層是一個數組,數組里面存放是一個單向鏈表。
下面從HashMap的創建也就是構造器來看

?? ?public HashMap(int initialCapacity, float loadFactor) {
?? ??? ?//指定的初始容量小于0,拋出異常
? ? ? ? if (initialCapacity < 0)
? ? ? ? ? ? throw new IllegalArgumentException("Illegal initial capacity: " +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);
? ? ? ? //指定初始容量超過能分配的最大容量,設置為最大容量 ? ? ? ? ? ? ? ? ? ?
? ? ? ? if (initialCapacity > MAXIMUM_CAPACITY)
? ? ? ? ? ? initialCapacity = MAXIMUM_CAPACITY;
? ? ? ? //如果指定的加載因子為0或者不是數字,拋出異常
? ? ? ? if (loadFactor <= 0 || Float.isNaN(loadFactor))
? ? ? ? ? ? throw new IllegalArgumentException("Illegal load factor: " +
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?loadFactor);
? ? ? ? //設置加載因子 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
? ? ? ? this.loadFactor = loadFactor;
? ? ? ? //設置閾值為初始容量的2的n次方
? ? ? ? this.threshold = tableSizeFor(initialCapacity);
? ? }
? ? public HashMap(int initialCapacity) {
? ? ? ? this(initialCapacity, DEFAULT_LOAD_FACTOR);
? ? }
? ? public HashMap() {
? ? ?? ?//設置加載因子為默認加載因子0.75
? ? ? ? this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
? ? }
? ? public HashMap(Map<? extends K, ? extends V> m) {
? ? ? ? this.loadFactor = DEFAULT_LOAD_FACTOR;
? ? ? ? putMapEntries(m, false);
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
寫入鍵值對的具體方法

?? ?
?? ?public V put(K key, V value) {
? ? ? ? return putVal(hash(key), key, value, false, true);
? ? }
? ? static final int hash(Object key) {
? ? ? ? int h;
? ? ? ? //先獲取key的hashCode值,然后將hashCode無符號右移16位,然后將右移后的值與原來的hashCode值做異或運算
? ? ? ? return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
? ? }
? ??
? ? final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
? ? ? ? ? ? ? ? ? ?boolean evict) {
? ? ? ? Node<K,V>[] tab; Node<K,V> p; int n, i;
? ? ? ? //當前哈希桶是空或者長度是0,就初始化哈希桶
? ? ? ? if ((tab = table) == null || (n = tab.length) == 0)
? ? ? ? ? ? n = (tab = resize()).length;
? ? ? ? if ((p = tab[i = (n - 1) & hash]) == null)//確定元素存放在哪個桶,當該位置沒有元素的時候,新生成節點放入桶中,此時元素存放在數組中
? ? ? ? //其實,(n - 1) & hash 就是取當前hash值和數組容量的余數操作
? ? ? ? ? ? tab[i] = newNode(hash, key, value, null);
? ? ? ? else {//該位置存在元素
? ? ? ? ? ? Node<K,V> e; K k;
? ? ? ? ? ? if (p.hash == hash &&
? ? ? ? ? ? ? ? ((k = p.key) == key || (key != null && key.equals(k))))//與桶中第一個元素hash相等,key相等
? ? ? ? ? ? ? ? e = p;//用e指向第一個元素
? ? ? ? ? ? else if (p instanceof TreeNode)//該位置是紅黑樹,就放入樹中
? ? ? ? ? ? ? ? e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
? ? ? ? ? ? else {//是鏈表
? ? ? ? ? ? ?? ?//在鏈表末端插入節點
? ? ? ? ? ? ? ? for (int binCount = 0; ; ++binCount) {
? ? ? ? ? ? ? ? ?? ?//遍歷到鏈表尾部
? ? ? ? ? ? ? ? ? ? if ((e = p.next) == null) {
? ? ? ? ? ? ? ? ? ? ?? ?//尾部插入新節點
? ? ? ? ? ? ? ? ? ? ? ? p.next = newNode(hash, key, value, null);
? ? ? ? ? ? ? ? ? ? ? ? if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st ?達到節點數量閾值
? ? ? ? ? ? ? ? ? ? ? ? ? ? treeifyBin(tab, hash);//轉換為紅黑樹
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? if (e.hash == hash &&
? ? ? ? ? ? ? ? ? ? ? ? ((k = e.key) == key || (key != null && key.equals(k))))//判斷鏈表中節點的key與插入的key是否相等
? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? p = e;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? if (e != null) { // 在桶中找到key和hash與插入元素相等的節點
? ? ? ? ? ? ? ? V oldValue = e.value;//記錄桶中的該節點value
? ? ? ? ? ? ? ? if (!onlyIfAbsent || oldValue == null)
? ? ? ? ? ? ? ? ? ? e.value = value;//新值替換舊值
? ? ? ? ? ? ? ? afterNodeAccess(e);//為LinkedHashMap提供支持
? ? ? ? ? ? ? ? return oldValue;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? ++modCount;
? ? ? ? if (++size > threshold)//超過閾值擴容
? ? ? ? ? ? resize();
? ? ? ? afterNodeInsertion(evict);//為LinkedHashMap提供支持
? ? ? ? return null;
? ? }
? ??
? ? //初始化或擴容
? ? final Node<K,V>[] resize() {
? ? ? ? Node<K,V>[] oldTab = table;
? ? ? ? //擴容前的哈希桶長度
? ? ? ? int oldCap = (oldTab == null) ? 0 : oldTab.length;
? ? ? ? //擴容前的閾值
? ? ? ? int oldThr = threshold;
? ? ? ? //擴容后的哈希桶長度和閾值
? ? ? ? int newCap, newThr = 0;
? ? ? ? if (oldCap > 0) {//哈希桶數組不為空
? ? ? ? ? ? if (oldCap >= MAXIMUM_CAPACITY) {//超過所能分配的最大空
? ? ? ? ? ? ? ? threshold = Integer.MAX_VALUE;//就賦值為整數的最大閾值
? ? ? ? ? ? ? ? return oldTab;
? ? ? ? ? ? }
? ? ? ? ? ? else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
? ? ? ? ? ? ? ? ? ? ?oldCap >= DEFAULT_INITIAL_CAPACITY)//雙倍擴容空間后小于所能分配的最大空間,并且大于默認空間16
? ? ? ? ? ? ? ? newThr = oldThr << 1; // 雙倍擴容閾值
? ? ? ? }
? ? ? ? else if (oldThr > 0) //當哈希桶是空,并且閾值大于0,設置初始容量為閾值
? ? ? ? ? ? newCap = oldThr;
? ? ? ? else { ?// 哈希桶是空,初始閾值也是0的時候
? ? ? ? ? ? newCap = DEFAULT_INITIAL_CAPACITY;//設置初始容量為16
? ? ? ? ? ? newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);//閾值為默認加載因子(0.75)*默認空間(16)
? ? ? ? }
? ? ? ? if (newThr == 0) {//新的閾值是0,計算閾值
? ? ? ? ? ? float ft = (float)newCap * loadFactor;
? ? ? ? ? ? newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
? ? ? ? ? ? ? ? ? ? ? (int)ft : Integer.MAX_VALUE);
? ? ? ? }
? ? ? ? threshold = newThr;//設置閾值
? ? ? ? @SuppressWarnings({"rawtypes","unchecked"})
? ? ? ? Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];//創建哈希桶數組
? ? ? ? table = newTab;//引用指向新的哈希桶數組
? ? ? ? if (oldTab != null) {//當舊的哈希桶數組不為空,需要將Node對象值復制到新哈希桶數組
? ? ? ? ? ? for (int j = 0; j < oldCap; ++j) {//遍歷舊的哈希桶
? ? ? ? ? ? ? ? Node<K,V> e;
? ? ? ? ? ? ? ? if ((e = oldTab[j]) != null) {//舊的哈希桶在節點j處不為空,e指向
? ? ? ? ? ? ? ? ? ? oldTab[j] = null;//將舊的哈希桶j節點設為空,方便gc
? ? ? ? ? ? ? ? ? ? if (e.next == null)//后面沒有Node了,也就是沒有元素沖突
? ? ? ? ? ? ? ? ? ? ? ? newTab[e.hash & (newCap - 1)] = e;//對e的哈希值對數組的新長度求模獲取存儲位置
? ? ? ? ? ? ? ? ? ? else if (e instanceof TreeNode)//如果e是紅黑樹類型,添加到紅黑樹
? ? ? ? ? ? ? ? ? ? ? ? ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
? ? ? ? ? ? ? ? ? ? else { // 因為擴容是容量翻倍,所以原鏈表上的每個節點,現在可能存放在原來的下標,即低位, 或者擴容后的下標,即高位。 高位= 低位+原哈希桶容量
? ? ? ? ? ? ? ? ? ? ? ? Node<K,V> loHead = null, loTail = null;//低位鏈表頭尾節點
? ? ? ? ? ? ? ? ? ? ? ? Node<K,V> hiHead = null, hiTail = null;//高位鏈表頭尾節點
? ? ? ? ? ? ? ? ? ? ? ? Node<K,V> next;//臨時節點
? ? ? ? ? ? ? ? ? ? ? ? do {
? ? ? ? ? ? ? ? ? ? ? ? ? ? next = e.next;
? ? ? ? ? ? ? ? ? ? ? ? ? ? //利用哈希值 與 舊的容量,可以得到哈希值去模后,是大于等于oldCap還是小于oldCap,等于0代表小于oldCap,應該存放在低位,否則存放在高位
? ? ? ? ? ? ? ? ? ? ? ? ? ? if ((e.hash & oldCap) == 0) {//節點e的哈希值與舊哈希桶數組的長度做與運算為0
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (loTail == null)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? loHead = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? loTail.next = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? loTail = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (hiTail == null)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? hiHead = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? else
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? hiTail.next = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? hiTail = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? } while ((e = next) != null);//循環到鏈表結束
? ? ? ? ? ? ? ? ? ? ? ? if (loTail != null) {//將低位鏈表存放在原index處
? ? ? ? ? ? ? ? ? ? ? ? ? ? loTail.next = null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? newTab[j] = loHead;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? if (hiTail != null) {//高位鏈表存放在新index處
? ? ? ? ? ? ? ? ? ? ? ? ? ? hiTail.next = null;
? ? ? ? ? ? ? ? ? ? ? ? ? ? newTab[j + oldCap] = hiHead;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return newTab;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
刪除元素部分

?? ?//存在key映射就刪除
?? ?public V remove(Object key) {
? ? ? ? Node<K,V> e;
? ? ? ? return (e = removeNode(hash(key), key, null, false, true)) == null ?
? ? ? ? ? ? null : e.value;
? ? }
? ? final Node<K,V> removeNode(int hash, Object key, Object value,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?boolean matchValue, boolean movable) {
? ? ? ? Node<K,V>[] tab; Node<K,V> p; int n, index;
? ? ? ? if ((tab = table) != null && (n = tab.length) > 0 &&
? ? ? ? ? ? (p = tab[index = (n - 1) & hash]) != null) {//哈希桶不是空,并且key存在哈希桶中,p指向和key同一位置的哈希桶中的第一個元素
? ? ? ? ? ? //node是待刪除節點
? ? ? ? ? ? Node<K,V> node = null, e; K k; V v;
? ? ? ? ? ? if (p.hash == hash &&
? ? ? ? ? ? ? ? ((k = p.key) == key || (key != null && key.equals(k))))//和第一個元素一致
? ? ? ? ? ? ? ? node = p;
? ? ? ? ? ? else if ((e = p.next) != null) {//循環遍歷找到待刪除節點
? ? ? ? ? ? ? ? if (p instanceof TreeNode)//是紅黑樹類型
? ? ? ? ? ? ? ? ? ? node = ((TreeNode<K,V>)p).getTreeNode(hash, key);
? ? ? ? ? ? ? ? else {
? ? ? ? ? ? ? ? ? ? do {
? ? ? ? ? ? ? ? ? ? ? ? if (e.hash == hash &&
? ? ? ? ? ? ? ? ? ? ? ? ? ? ((k = e.key) == key ||
? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(key != null && key.equals(k)))) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? node = e;
? ? ? ? ? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? p = e;
? ? ? ? ? ? ? ? ? ? } while ((e = e.next) != null);
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? ? ? //待刪除節點不是空,且 matchValue為false(如果matchValue為true,則僅在值相等時刪除),或者值相等
? ? ? ? ? ? if (node != null && (!matchValue || (v = node.value) == value ||
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(value != null && value.equals(v)))) {
? ? ? ? ? ? ? ? if (node instanceof TreeNode)//待刪除節點屬于紅黑樹類型
? ? ? ? ? ? ? ? ? ? ((TreeNode<K,V>)node).removeTreeNode(this, tab, movable);
? ? ? ? ? ? ? ? else if (node == p)//待刪除節點是鏈表頭
? ? ? ? ? ? ? ? ? ? tab[index] = node.next;
? ? ? ? ? ? ? ? else//待刪除節點在表中間
? ? ? ? ? ? ? ? ? ? p.next = node.next;
? ? ? ? ? ? ? ? ++modCount;
? ? ? ? ? ? ? ? --size;
? ? ? ? ? ? ? ? afterNodeRemoval(node);//為LinkedHashMap提供的回調
? ? ? ? ? ? ? ? return node;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return null;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
獲取元素,和上面都類似

?? ?public V get(Object key) {
? ? ? ? Node<K,V> e;
? ? ? ? return (e = getNode(hash(key), key)) == null ? null : e.value;
? ? }
? ? final Node<K,V> getNode(int hash, Object key) {
? ? ? ? Node<K,V>[] tab; Node<K,V> first, e; int n; K k;
? ? ? ? if ((tab = table) != null && (n = tab.length) > 0 &&
? ? ? ? ? ? (first = tab[(n - 1) & hash]) != null) {
? ? ? ? ? ? if (first.hash == hash && // always check first node
? ? ? ? ? ? ? ? ((k = first.key) == key || (key != null && key.equals(k))))
? ? ? ? ? ? ? ? return first;
? ? ? ? ? ? if ((e = first.next) != null) {
? ? ? ? ? ? ? ? if (first instanceof TreeNode)//去紅黑樹中取
? ? ? ? ? ? ? ? ? ? return ((TreeNode<K,V>)first).getTreeNode(hash, key);
? ? ? ? ? ? ? ? do {//遍歷鏈表獲取
? ? ? ? ? ? ? ? ? ? if (e.hash == hash &&
? ? ? ? ? ? ? ? ? ? ? ? ((k = e.key) == key || (key != null && key.equals(k))))
? ? ? ? ? ? ? ? ? ? ? ? return e;
? ? ? ? ? ? ? ? } while ((e = e.next) != null);
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return null;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HashMap底層采用數組、鏈表、紅黑樹的方式來實現;初始化默認容量是16,加載因子是0.75,也就是容量達到12就會進行擴容。HashMap中元素key可以存null,但是只能存一個,key不能重復,value可以重復,判斷key重復的標準是根據hash值,如果hash值一致,再根據equals,只有hash和equals都一致的時候才認為重復;當hash值一致,equals不一致,會存儲在數組同一個下標位置(數組中存儲的就是鏈表或者紅黑樹),當鏈表節點數大于8就會轉為紅黑樹,當紅黑樹節點數小于6就會轉為鏈表。擴容是按一倍擴容

2.LinkedHashMap(部分源碼)
?? ?/**
? ? ?* HashMap.Node subclass for normal LinkedHashMap entries.
? ? ?*/
? ? static class Entry<K,V> extends HashMap.Node<K,V> {
? ? ? ? Entry<K,V> before, after;
? ? ? ? Entry(int hash, K key, V value, Node<K,V> next) {
? ? ? ? ? ? super(hash, key, value, next);
? ? ? ? }
? ? }
? ??
? ? transient LinkedHashMap.Entry<K,V> head;//雙鏈表頭
? ?
? ? transient LinkedHashMap.Entry<K,V> tail;//雙鏈表尾

? ? //用來指定LinkedHashMap的迭代順序,true表示基于訪問的順序來排列,就是最近使用的Entry放在鏈表的最末尾;false表示基于插入順序
? ? final boolean accessOrder;

?? ?//默認初始容量(16),默認加載因子(0.75)
? ? public LinkedHashMap() {
? ? ? ? super();
? ? ? ? accessOrder = false;
? ? }
? ? //指定初始容量和加載因子
?? ?public LinkedHashMap(int initialCapacity, float loadFactor) {
? ? ? ? super(initialCapacity, loadFactor);
? ? ? ? accessOrder = false;
? ? }
?? ?//插入元素是使用的HashMap的put實現,HashMap中put的是內部類的Node類型節點,該節點不具備和LinkedHashMap內部類Entry和子類型節點組成鏈表的能力,于是重寫了newNode方法
?? ?Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {
? ? ? ? LinkedHashMap.Entry<K,V> p =
? ? ? ? ? ? new LinkedHashMap.Entry<>(hash, key, value, e);
? ? ? ? linkNodeLast(p);//將Entry接在雙向鏈表尾部
? ? ? ? return p;
? ? }

? ? // 連接到鏈表末尾(put元素后會回調的方法,維護鏈表結構)
? ? private void linkNodeLast(LinkedHashMap.Entry<K,V> p) {
? ? ? ? LinkedHashMap.Entry<K,V> last = tail;
? ? ? ? tail = p;//尾結點為當前插入節點
? ? ? ? if (last == null)//鏈表尾部節點是空,表示鏈表為空,插入第一個節點,頭尾節點是同一個
? ? ? ? ? ? head = p;
? ? ? ? else {
? ? ? ? ? ? p.before = last;//插入節點的前驅指向之前的尾結點
? ? ? ? ? ? last.after = p;//之前尾結點的后繼指向插入的節點
? ? ? ? }
? ? }
?? ?//連接到鏈表末尾(put元素后會回調的方法,維護鏈表結構)
?? ?void afterNodeRemoval(Node<K,V> e) {?
?? ??? ?//獲取要刪除節點的前驅(上一個節點)和后繼(下一個節點)
? ? ? ? LinkedHashMap.Entry<K,V> p =
? ? ? ? ? ? (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;
? ? ? ? p.before = p.after = null;//將要刪除節點的前驅和后繼指向清空
? ? ? ? if (b == null)//如果前驅是空,要刪除的就是頭結點
? ? ? ? ? ? head = a;//將要刪除節點的后繼設為頭結點
? ? ? ? else
? ? ? ? ? ? b.after = a;//將前驅的后繼指向要刪除節點的后繼
? ? ? ? if (a == null)//后繼是空,要刪除的是尾結點
? ? ? ? ? ? tail = b;//前驅作為尾結點
? ? ? ? else
? ? ? ? ? ? a.before = b;//將后繼的前驅指向要刪除節點的前驅
? ? }
? ? //重寫了獲取元素方法
?? ?public V get(Object key) {
? ? ? ? Node<K,V> e;
? ? ? ? if ((e = getNode(hash(key), key)) == null)//調用HashMap的getNode方法獲取Node節點
? ? ? ? ? ? return null;
? ? ? ? if (accessOrder)//判斷是按插入順序還是訪問順序
? ? ? ? ? ? afterNodeAccess(e);//按訪問順序的鏈表維護操作
? ? ? ? return e.value;
? ? }
? ? //將節點移到鏈表尾部
? ? void afterNodeAccess(Node<K,V> e) {
? ? ? ? LinkedHashMap.Entry<K,V> last;
? ? ? ? if (accessOrder && (last = tail) != e) {//默認accessOrder是false按插入順序,開啟了順序訪問并且當前訪問節點不是尾結點
? ? ? ? ? ? LinkedHashMap.Entry<K,V> p =
? ? ? ? ? ? ? ? (LinkedHashMap.Entry<K,V>)e, b = p.before, a = p.after;//獲取訪問節點的前驅和后繼
? ? ? ? ? ? p.after = null;//訪問節點要移動到鏈表尾部,后繼指向設成空
? ? ? ? ? ? if (b == null)//前驅是空,訪問的為頭結點
? ? ? ? ? ? ? ? head = a;//將訪問節點的后繼設成頭結點
? ? ? ? ? ? else
? ? ? ? ? ? ? ? b.after = a;//前驅的后繼指向改為訪問節點的后繼
? ? ? ? ? ? if (a != null)//訪問節點的后繼不是空,不是尾結點
? ? ? ? ? ? ? ? a.before = b;//后繼的前驅指向訪問節點的前驅
? ? ? ? ? ? else
? ? ? ? ? ? ? ? last = b;
? ? ? ? ? ? if (last == null)
? ? ? ? ? ? ? ? head = p;
? ? ? ? ? ? else {
? ? ? ? ? ? ? ? p.before = last;//訪問節點的前驅指向原本的尾結點
? ? ? ? ? ? ? ? last.after = p;//原本的尾結點的后繼指向訪問節點
? ? ? ? ? ? }
? ? ? ? ? ? tail = p;//尾部節點設為訪問節點
? ? ? ? ? ? ++modCount;
? ? ? ? }
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
擴展一下,通過LinkedHashMap實現一個簡單的LRU緩存策略。
首先什么是LRU緩存策略,這是一種緩存淘汰機制,我們的緩存都是有限的,緩存滿了的情況下,怎么給新內容騰位置。LRU緩存策略就是我們認為最近使用的數據是有用的,許久不用的數據是無用的,優先刪除許久不用的數據
在LinkedHashMap源碼中有下面的方法為LRU的實現提供了支持

?? ?//改方法在put元素的時候有被調用,參數【evict】官方解釋是,false的時候表屬于創建模式
?? ?void afterNodeInsertion(boolean evict) {?
? ? ? ? LinkedHashMap.Entry<K,V> first;
? ? ? ? //表不是創建模式(表已經創建),并且頭結點不是空(表中有元素),并且自定義策略通過的時候,移除節點
? ? ? ? if (evict && (first = head) != null && removeEldestEntry(first)) {
? ? ? ? ? ? K key = first.key;
? ? ? ? ? ? removeNode(hash(key), key, null, false, true);
? ? ? ? }
? ? }
? ? //通過LinkedHashMap來實現LRU,可以通過重寫該方法實現自定義的LRU緩存策略
? ? protected boolean removeEldestEntry(Map.Entry<K,V> eldest) {
? ? ? ? return false;
? ? }
?? ?//重寫了父類方法,和get差不多,只是在表中沒有對應鍵值對的時候,返回的是我們的默認值
? ? public V getOrDefault(Object key, V defaultValue) {
? ? ? ?Node<K,V> e;
? ? ? ?if ((e = getNode(hash(key), key)) == null)
? ? ? ? ? ?return defaultValue;
? ? ? ?if (accessOrder)
? ? ? ? ? ?afterNodeAccess(e);
? ? ? ?return e.value;
? ?}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
通過繼承LinkedHashMap來實現LRU

class LRUCache extends LinkedHashMap<String,String>{
?? ?private int capacity;//容量
?? ?
? ? public LRUCache(int capacity) {
? ? ? ? super(capacity, 0.75F, true);//使用默認加載因子0.75,自定義指定容量
? ? ? ? this.capacity = capacity;
? ? }
? ??
? ? public int get(int key) {
? ? ? ? return super.getOrDefault(key, -1);
? ? }
? ??
? ? public void put(int key, int value) {
? ? ? ? super.put(key, value);
? ? }
? ? /**
? ? * 判斷節點數是否超限
? ? * @param eldest
? ? * @return 超限返回 true, 否則返回false
? ? */
? ? @Override
? ? protected boolean removeEldestEntry(Map.Entry<Integer, Integer> eldest) {
? ? ? ? return size() > capacity;
? ? }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
LinkedHashMap是HashMap的子類,繼承了父類的屬性,在添加和刪除元素LinkedHashMap都是直接使用的父類的方法,不同的是LinkedHashMap采用了雙向鏈表維護元素順序,重寫了用來維護鏈表的回調方法

3.TreeMap(部分源碼)
?? ?//用于維護TreeMap中的順序的比較器,使用鍵的自然排序它就是null
?? ?private final Comparator<? super K> comparator;
?? ?//根節點
?? ?private transient Entry<K,V> root;
?? ?//Entry樹的節點類
?? ?static final class Entry<K,V> implements Map.Entry<K,V> {
? ? ? ? K key;//鍵
? ? ? ? V value;//值
? ? ? ? Entry<K,V> left;//左節點
? ? ? ? Entry<K,V> right;//右節點
? ? ? ? Entry<K,V> parent;//父節點
? ? ? ? boolean color = BLACK;
? ? ? ??
? ? ? ? Entry(K key, V value, Entry<K,V> parent) {
? ? ? ? ? ? this.key = key;
? ? ? ? ? ? this.value = value;
? ? ? ? ? ? this.parent = parent;
? ? ? ? }
?? ?}
?? ?
?? ?//創建默認的TreeMap,默認使用鍵的自然排序;前提是插入到TreeMap中的所有鍵都必須實現了Comparator接口
?? ?public TreeMap() {
? ? ? ? comparator = null;
? ? }
? ? //創建的TreeMap根據給定的排序器排序,如果為null就按自然排序
? ? public TreeMap(Comparator<? super K> comparator) {
? ? ? ? this.comparator = comparator;
? ? }
? ? //創建新的TreeMap并將指定map中的元素添加到TreeMap
?? ?public TreeMap(Map<? extends K, ? extends V> m) {
? ? ? ? comparator = null;
? ? ? ? putAll(m);
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
從上面可以看出來TreeMap的底層是紅黑樹來實現的,下面看看TreeMap是如何添加元素的

?? ?public V put(K key, V value) {
? ? ? ? Entry<K,V> t = root;//根節點
? ? ? ? if (t == null) {//根節點是null,TreeMap里面沒有元素
? ? ? ? ? ? compare(key, key); // type (and possibly null) check
? ? ? ? ? ? root = new Entry<>(key, value, null);//新建節點,設置成根節點
? ? ? ? ? ? size = 1;
? ? ? ? ? ? modCount++;
? ? ? ? ? ? return null;
? ? ? ? }
? ? ? ? int cmp;
? ? ? ? Entry<K,V> parent;//父節點
? ? ? ??
? ? ? ? Comparator<? super K> cpr = comparator;// 比較器
? ? ? ? if (cpr != null) {//按比較器排序,循環查找key要插入的位置
? ? ? ? ? ? do {
? ? ? ? ? ? ? ? parent = t;//記錄循環的節點,最后循環到的節點就是要插入節點的父節點
? ? ? ? ? ? ? ? cmp = cpr.compare(key, t.key);//比較新插入的key和當前節點key的大小
? ? ? ? ? ? ? ? if (cmp < 0)//新插入的key要小
? ? ? ? ? ? ? ? ? ? t = t.left;//將當前節點的左子節點作為新的比較節點
? ? ? ? ? ? ? ? else if (cmp > 0)//新插入的key要大
? ? ? ? ? ? ? ? ? ? t = t.right;//將當前節點的右子節點作為新的比較節點
? ? ? ? ? ? ? ? else//當前節點key和新插入的key相等,覆蓋value
? ? ? ? ? ? ? ? ? ? return t.setValue(value);
? ? ? ? ? ? } while (t != null);//t是null,表示已經沒有可以比較的節點,已經找到插入位置
? ? ? ? }
? ? ? ? else {//按自然排序,循環查找key要插入的位置
? ? ? ? ? ? if (key == null)//比較器是null,需要使用key作為比較器來進行比較,并且key必須實現了Comparable接口
? ? ? ? ? ? ? ? throw new NullPointerException();
? ? ? ? ? ? @SuppressWarnings("unchecked")
? ? ? ? ? ? ? ? Comparable<? super K> k = (Comparable<? super K>) key;
? ? ? ? ? ? do {
? ? ? ? ? ? ? ? parent = t;//記錄循環節點,最后循環到的節點就是要插入節點的父節點
? ? ? ? ? ? ? ? cmp = k.compareTo(t.key);//根據實現的compareto方法來比較當前節點key和新插入key的大小
? ? ? ? ? ? ? ? if (cmp < 0)//新插入的key要小
? ? ? ? ? ? ? ? ? ? t = t.left;//將//新插入的key要大當前節點的左子節點作為新的比較節點
? ? ? ? ? ? ? ? else if (cmp > 0)//新插入的key要大
? ? ? ? ? ? ? ? ? ? t = t.right;//將當前節點的右子節點作為新的比較節點
? ? ? ? ? ? ? ? else//當前節點key和新插入的key相等,覆蓋value
? ? ? ? ? ? ? ? ? ? return t.setValue(value);
? ? ? ? ? ? } while (t != null);//t是null,表示已經沒有可以比較的節點,已經找到插入位置
? ? ? ? }
? ? ? ? Entry<K,V> e = new Entry<>(key, value, parent);//新建節點
? ? ? ? if (cmp < 0)//新節點key要小于父節點的key,插入父節點的左側
? ? ? ? ? ? parent.left = e;
? ? ? ? else新節點key要大于等于父節點的key,插入父節點的右側
? ? ? ? ? ? parent.right = e;
? ? ? ? fixAfterInsertion(e);//新插入節點,為了保持紅黑樹平衡需要對樹進行調整(這一步涉及紅黑樹操作比較復雜,這里不做闡述)
? ? ? ? size++;
? ? ? ? modCount++;
? ? ? ? return null;
? ? }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
4.Hashtable(部分源碼)
?? ?//哈希表數據
? ? private transient Entry<?,?>[] table;
?? ?//哈希表條目總數
? ? private transient int count;
? ? //閾值
?? ?private int threshold;
?? ?//加載因子
?? ?private float loadFactor;
?? ?//指定初始容量和加載因子
?? ?public Hashtable(int initialCapacity, float loadFactor) {
? ? ? ? if (initialCapacity < 0)
? ? ? ? ? ? throw new IllegalArgumentException("Illegal Capacity: "+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?initialCapacity);
? ? ? ? if (loadFactor <= 0 || Float.isNaN(loadFactor))
? ? ? ? ? ? throw new IllegalArgumentException("Illegal Load: "+loadFactor);
? ? ? ? if (initialCapacity==0)
? ? ? ? ? ? initialCapacity = 1;
? ? ? ? this.loadFactor = loadFactor;
? ? ? ? table = new Entry<?,?>[initialCapacity];
? ? ? ? threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1);
? ? }
? ? //指定初始容量,默認加載因子
? ? public Hashtable(int initialCapacity) {
? ? ? ? this(initialCapacity, 0.75f);
? ? }
?? ?//默認初始容量11,加載因子0.75
?? ?public Hashtable() {
? ? ? ? this(11, 0.75f);
? ? }

?? ?private static class Entry<K,V> implements Map.Entry<K,V> {
? ? ? ? final int hash;
? ? ? ? final K key;
? ? ? ? V value;
? ? ? ? Entry<K,V> next;

? ? ? ? protected Entry(int hash, K key, V value, Entry<K,V> next) {
? ? ? ? ? ? this.hash = hash;
? ? ? ? ? ? this.key = ?key;
? ? ? ? ? ? this.value = value;
? ? ? ? ? ? this.next = next;
? ? ? ? }
? ? ?}

添加元素部分

?? ?public synchronized V put(K key, V value) {
? ? ? ? if (value == null) {//值不能為null
? ? ? ? ? ? throw new NullPointerException();
? ? ? ? }

? ? ? ? // Makes sure the key is not already in the hashtable.
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? int hash = key.hashCode();//獲取key的哈希值
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;//通過哈希值找到存儲位置
? ? ? ? @SuppressWarnings("unchecked")
? ? ? ? Entry<K,V> entry = (Entry<K,V>)tab[index];//取得該位置的entry對象
? ? ? ? for(; entry != null ; entry = entry.next) {//遍歷該位置鏈表
? ? ? ? ? ? if ((entry.hash == hash) && entry.key.equals(key)) {//key相同,覆蓋舊值
? ? ? ? ? ? ? ? V old = entry.value;
? ? ? ? ? ? ? ? entry.value = value;
? ? ? ? ? ? ? ? return old;
? ? ? ? ? ? }
? ? ? ? }
?? ??? ?//添加entry對象
? ? ? ? addEntry(hash, key, value, index);
? ? ? ? return null;
? ? }
? ? private void addEntry(int hash, K key, V value, int index) {
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? if (count >= threshold) {//當前容量超過閾值,需要擴容按2n+1
? ? ? ? ? ? rehash();
? ? ? ? ? ? tab = table;
? ? ? ? ? ? hash = key.hashCode();
? ? ? ? ? ? index = (hash & 0x7FFFFFFF) % tab.length;//取模運算
? ? ? ? }
? ? ? ? @SuppressWarnings("unchecked")
? ? ? ? Entry<K,V> e = (Entry<K,V>) tab[index];//取得該位置的entry對象
? ? ? ? tab[index] = new Entry<>(hash, key, value, e);//創建新節點,新節點插入鏈表首部
? ? ? ? count++;
? ? ? ? modCount++;
? ? }
? ? protected void rehash() {
? ? ? ? int oldCapacity = table.length;//當前哈希表長度
? ? ? ? Entry<?,?>[] oldMap = table;//舊哈希表
? ? ? ? int newCapacity = (oldCapacity << 1) + 1;//新容量,相當于2n+1
? ? ? ? if (newCapacity - MAX_ARRAY_SIZE > 0) {//新容量超過可分配最大空間,默認使用最大空間
? ? ? ? ? ? if (oldCapacity == MAX_ARRAY_SIZE)
? ? ? ? ? ? ? ? // Keep running with MAX_ARRAY_SIZE buckets
? ? ? ? ? ? ? ? return;
? ? ? ? ? ? newCapacity = MAX_ARRAY_SIZE;
? ? ? ? }
? ? ? ? Entry<?,?>[] newMap = new Entry<?,?>[newCapacity];//創建新容量大小的哈希表
? ? ? ? modCount++;
? ? ? ? threshold = (int)Math.min(newCapacity * loadFactor, MAX_ARRAY_SIZE + 1);//閾值
? ? ? ? table = newMap;//引用指向

? ? ? ? for (int i = oldCapacity ; i-- > 0 ;) {//將舊哈希表中的元素復制到新哈希表
? ? ? ? ? ? for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) {
? ? ? ? ? ? ? ? Entry<K,V> e = old;
? ? ? ? ? ? ? ? old = old.next;

? ? ? ? ? ? ? ? int index = (e.hash & 0x7FFFFFFF) % newCapacity;
? ? ? ? ? ? ? ? e.next = (Entry<K,V>)newMap[index];
? ? ? ? ? ? ? ? newMap[index] = e;
? ? ? ? ? ? }
? ? ? ? }
? ? }

移除元素部分

?? ?public synchronized V remove(Object key) {
? ? ? ? Entry<?,?> tab[] = table;//當前哈希表
? ? ? ? int hash = key.hashCode();//key的哈希值
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;//取模,計算key在哈希表的位置
? ? ? ? @SuppressWarnings("unchecked")
? ? ? ? Entry<K,V> e = (Entry<K,V>)tab[index];//當前位置的鏈表首部entry
? ? ? ? for(Entry<K,V> prev = null ; e != null ; prev = e, e = e.next) {//遍歷鏈表
? ? ? ? ? ? if ((e.hash == hash) && e.key.equals(key)) {//找到鏈表中哈希值和equals都相同的節點
? ? ? ? ? ? ? ? if (prev != null) {//要移除節點的上一個節點不是null,表示不是頭部,將后繼指向修改
? ? ? ? ? ? ? ? ? ? prev.next = e.next;
? ? ? ? ? ? ? ? } else {//移除節點是頭部,將移除節點的后繼節點用作鏈表頭部,放入哈希表當前位置
? ? ? ? ? ? ? ? ? ? tab[index] = e.next;
? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? modCount++;
? ? ? ? ? ? ? ? count--;
? ? ? ? ? ? ? ? V oldValue = e.value;
? ? ? ? ? ? ? ? e.value = null;//清空值
? ? ? ? ? ? ? ? return oldValue;//返回移除key對應的value
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return null;//沒找到對應key,返回null
? ? }

獲取元素

?? ?public synchronized V get(Object key) {
? ? ? ? Entry<?,?> tab[] = table;
? ? ? ? int hash = key.hashCode();
? ? ? ? int index = (hash & 0x7FFFFFFF) % tab.length;
? ? ? ? for (Entry<?,?> e = tab[index] ; e != null ; e = e.next) {//遍歷該位置鏈表
? ? ? ? ? ? if ((e.hash == hash) && e.key.equals(key)) {//找到對應的entry對象
? ? ? ? ? ? ? ? return (V)e.value;//返回值
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? return null;//沒找到返回null
? ? }

Hashtable和HashMap類似,都是采用哈希表和鏈表來實現。不同的是,
1.在構建的時候,Hashtable的默認初始容量是11,HashMap是16
2.添加元素的時候,Hashtable對key和value做了null驗證,保證了key和value不能為null,而HashMap是可以插入null鍵值對的
3.擴容的時候,Hashtable是按2n+1,HashMap是2n
4.在獲取元素和移除元素的方法上Hashtable是有synchronized 關鍵字的,其他讀寫元素的方法也有,Hashtable是線程安全的

總結
List:元素有序、可重復集合,可通過索引訪問元素
ArrayList:底層基于數組實現,默認初始容量是10,擴容的時候按左位移運算擴容,每次擴容都需要創建數組,可以指定合適的初始化容量避免多次擴容。基于數組的原因,在隨機訪問上效率高;當插入元素到數組中間位置的時候,該位置后面的元素也需要全部后移一位,刪除元素的時候需要前移,涉及多個元素操作的時候插入刪除效率就會偏低(并且擴容操作也在插入的時候進行)
LinkedList:基于雙向鏈表實現,隨機訪問元素效率要差,插入刪除元素效率要高
Vector:基于數組實現,和ArrayList相似,初始容量也是10,操作也基本相同,不同的是擴容默認按一倍擴容,并且它是線程安全的

Set:元素不可重復
HashSet:基于HashMap來實現
LinkedHashSet:HashSet的子類,基于LinkedHashMap實現
TreeSet:基于TreeMap實現

Map:存儲鍵值對,key不允許重復
HashMap:不保證元素的插入順序,初始容量16,默認加載因子0.75,采用數組、鏈表、紅黑樹來實現,數組中存儲的是鏈表或者紅黑樹,當鏈表節點數大于8就會轉為紅黑樹,紅黑樹節點數小于6就會轉為鏈表,按一倍擴容,通過哈希值和equals來判斷key是否重復
LinkedHashMap:HashMap的子類,在HashMap的基礎上添加了鏈表來維護元素的順序,LinkedHashMap中的accessOrder屬性默認是false,也就是默認維護元素的插入順序,當設置true的時候維護元素的訪問順序,也就是get過后,會將訪問的元素移動到鏈表尾部,需要維護元素順序,性能比HashMap低
TreeMap:一個有序的鍵值對集合,不能存儲null,基于紅黑樹實現,有兩種排序方式,自然排序和定制排序
自然排序:所有key必須實現Comparable接口,并且所有的key應該是同一個類得對象,否則會拋出ClassCastException
定制排序:創建TreeMap時,傳入一個Comparator對象,該對象負責對TreeMap中的所有key進行排序
————————————————
版權聲明:本文為CSDN博主「紅了個籮蘿卜」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/qq_42432033/article/details/118359434

總結

以上是生活随笔為你收集整理的JAVA集合源码的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

又黄又刺激又爽的视频 | 亚洲经典视频在线观看 | 亚洲欧洲成人精品av97 | 亚洲国产精品免费 | 中文字幕精品久久 | 激情五月在线视频 | 久久污视频| 91精品久久久久久综合乱菊 | 国产精品理论在线观看 | 色欧美88888久久久久久影院 | 久久久久久久久爱 | 国产成人免费在线观看 | 中文字幕免费在线 | 亚洲欧美少妇 | 欧美日本高清视频 | 国内精品久久久久影院优 | 精品久久久久久亚洲综合网 | 久久精品黄色 | 69久久夜色精品国产69 | 久久99亚洲精品久久久久 | 国产 日韩 欧美 自拍 | 国产成人在线综合 | 人人澡av| а中文在线天堂 | 久久久久久久久久久影视 | 91亚洲精品久久久蜜桃借种 | 欧美日韩国语 | 一级欧美黄 | 精品五月天 | 久久久伦理| 国产无遮挡又黄又爽在线观看 | 五月色婷 | 黄色电影在线免费观看 | 天天色草| 99精品免费 | 国产最新在线 | 在线成人一区 | 日本性生活免费看 | 东方av免费在线观看 | 日韩黄色免费在线观看 | 天天天色| 亚洲欧美一区二区三区孕妇写真 | 亚洲 欧美 日韩 综合 | 午夜.dj高清免费观看视频 | 亚洲精品字幕 | 国产精品一区二区中文字幕 | 日韩在线电影一区 | 在线看91| 亚洲激情六月 | 久久五月婷婷综合 | 亚洲精品资源在线 | 欧美人交a欧美精品 | 午夜视频久久久 | 99草视频在线观看 | 中文字幕在线观看一区 | 精品久久久久久久久中文字幕 | 欧美精品一区二区蜜臀亚洲 | 久久精品一区八戒影视 | 日韩精品一区二区在线视频 | 91免费试看 | 在线成人一区二区 | 中文免费 | 麻豆播放 | 国外成人在线视频网站 | 操操操日日日 | 免费精品视频在线观看 | 久久99在线视频 | 九九久久免费视频 | 国产精品福利小视频 | 麻豆系列在线观看 | 久久a免费视频 | 亚洲桃花综合 | 久久一区精品 | 久久在线视频在线 | 国产精品一区二区美女视频免费看 | 国产特级毛片 | 日韩中文在线字幕 | 人成午夜视频 | a黄色| 亚洲最新在线 | 99热精品在线观看 | 国内精品视频在线播放 | av在线电影播放 | 国产精品18久久久久久首页狼 | 四虎国产精品免费观看视频优播 | av在线网站观看 | 波多野结衣亚洲一区二区 | 天天干天天干天天 | 日韩av免费观看网站 | 精品国产乱码久久久久久三级人 | 久久国产精品99久久久久久丝袜 | 91大神电影| 麻豆传媒精品 | 免费在线观看视频a | 国产手机视频在线播放 | 青青射 | 久久全国免费视频 | 久草免费在线视频观看 | 成人亚洲网 | 综合色伊人 | 中文字幕大全 | 久久精品久久精品 | 成人小视频在线观看免费 | 九九视频精品在线 | 日日干,天天干 | 久久99欧美 | 亚洲精品美女在线观看播放 | 中文字幕一区三区 | 国内精品亚洲 | 亚洲精品中文字幕在线观看 | 视频一区二区国产 | 999在线精品 | 日韩伦理一区二区三区av在线 | 成人毛片久久 | 五月天伊人 | 亚洲狠狠操 | 麻豆手机在线 | 国内久久 | 天天曰天天曰 | 日韩网站免费观看 | 中文在线| 99久久精品免费看国产四区 | 日韩免费一区二区在线观看 | 热久久视久久精品18亚洲精品 | 天天干天天搞天天射 | 天天曰天天爽 | 亚洲国产小视频在线观看 | 亚洲一区日韩精品 | 91视频成人免费 | 欧美激情综合五月色丁香 | 久久老司机精品视频 | 国产精品18久久久久vr手机版特色 | 精品久久久久_ | 亚洲免费av在线 | 97影视| 91精品入口 | 国产资源在线免费观看 | 天堂va在线高清一区 | 99热手机在线观看 | 免费视频久久久久久久 | 亚洲精品成人av在线 | 日本久久91 | 日韩激情三级 | 日本黄色免费观看 | 欧美日韩中文另类 | 四虎影视成人 | 久久精品视频国产 | 久草视频在线免费播放 | 丁香5月婷婷久久 | 色婷婷综合激情 | 久久久www免费电影网 | 狠狠色噜噜狠狠 | av在线专区| 亚洲性xxxx | 五月天丁香视频 | 香蕉国产91 | 中文字幕色在线视频 | 五月婷香 | 中日韩欧美精彩视频 | 欧美精品亚洲精品日韩精品 | 精品国产自在精品国产精野外直播 | 国产精品久久久久久久久久免费 | 成人sm另类专区 | 欧美精品午夜 | 国产精品欧美日韩在线观看 | 激情偷乱人伦小说视频在线观看 | 久久久久久久久网站 | 色综合在| 在线免费观看视频a | 天天弄天天操 | 美腿丝袜av | 日韩成人精品在线观看 | 国产精品久久久久久久久久久免费看 | 日韩在线视频网址 | 日韩av成人在线观看 | 精品国产一区二区三区日日嗨 | 91在线最新 | 91精品国产一区二区三区 | 免费毛片一区二区三区久久久 | 在线国产视频观看 | 亚洲精品美女在线 | 91久久精品一区二区二区 | www.午夜| 免费a v在线 | 久久久综合精品 | 国产精成人品免费观看 | 亚洲精品va | 亚洲欧美日韩在线看 | 久久黄视频| 91麻豆网| 国产亚洲精品久久久久久无几年桃 | 中文字幕欧美三区 | 日日摸日日 | 天天想夜夜操 | 亚洲精品国产第一综合99久久 | 波多野结衣资源 | 人人讲| 久久久夜色 | 国产一级免费在线 | 久久综合久久综合这里只有精品 | 日韩欧美在线视频一区二区三区 | 国产99免费| 国产成人av一区二区三区在线观看 | 在线免费观看国产精品 | 一区二三国产 | 丝袜一区在线 | 国产成人在线观看免费 | 国产精品成人免费精品自在线观看 | 一级片色播影院 | 欧美激情综合五月 | 五月婷婷中文字幕 | 97电院网手机版 | 又黄又爽又无遮挡免费的网站 | 成人动态视频 | 国产伦精品一区二区三区照片91 | 久草剧场| 狠狠精品 | 日韩在线色视频 | 免费在线观看国产黄 | 久久综合久久综合九色 | a久久久久| 国产成人三级一区二区在线观看一 | 黄色网址在线播放 | 中文字幕中文字幕在线中文字幕三区 | 国产精品色| 久久天天躁夜夜躁狠狠85麻豆 | 最近av在线 | 一区二区三区高清在线 | 日本黄色片一区二区 | 最新日韩在线 | 国产精品一区二区三区在线看 | 91自拍91 | 亚洲影视九九影院在线观看 | 伊人宗合| 精品久久久久久久久久久院品网 | 中文字幕在线观看免费高清电影 | 国产资源在线免费观看 | 国产精品毛片久久久久久久久久99999999 | 亚洲精品一区二区三区新线路 | www.天天射.com | 激情五月婷婷综合网 | 成人资源在线观看 | 国产蜜臀av | 久久香蕉一区 | 日韩系列在线 | 伊人黄| 国内久久精品视频 | 麻豆网站免费观看 | 99综合电影在线视频 | 国产精品麻豆免费版 | 国产精品日韩在线播放 | 日日夜日日干 | 香蕉久草在线 | www色婷婷com | 中文资源在线观看 | 久久精品中文视频 | 久久ww| 日韩综合一区二区三区 | 久久久免费 | 韩国精品视频在线观看 | 日韩中文免费视频 | 综合视频在线 | 韩国中文三级 | 久久优 | 97视频免费观看 | 成人国产精品久久久春色 | 亚洲成av| 亚洲丁香久久久 | 国内视频在线 | 国产精品美女久久久免费 | 日批在线观看 | 在线一二区 | 中文字幕人成不卡一区 | 久久久久成人免费 | 91高清视频| 在线观看 亚洲 | 美女黄濒 | 国产一线二线三线在线观看 | 亚洲天堂色婷婷 | 丝袜美腿av | 亚洲精品国产精品乱码不99热 | 最近中文字幕高清字幕在线视频 | 黄色成人91 | 亚洲黄色激情小说 | 成人亚洲精品国产www | 国产精品久久久久免费 | 99视频导航| 91视频在线| 日本高清免费中文字幕 | 欧美久久久影院 | 伊人久在线 | 免费网站在线观看人 | 日韩av影视在线观看 | 久草在线99 | 99免在线观看免费视频高清 | 韩日电影在线 | www五月天com | 久久综合九色综合欧美就去吻 | 蜜臀久久99精品久久久无需会员 | 蜜臀av在线一区二区三区 | www.夜夜夜 | 一色屋精品视频在线观看 | 69久久99精品久久久久婷婷 | 奇米四色影狠狠爱7777 | 国产又黄又爽又猛视频日本 | 久久国产精品久久久 | 精品国产乱码久久久久久浪潮 | 综合色婷婷 | av线上看| 蜜桃av观看 | 国产精品一级在线 | 欧美激情精品久久久久久 | 免费三级骚 | 亚洲有 在线 | 久久久精品视频网站 | 国产精品九九久久久久久久 | 亚洲伊人网在线观看 | 91高清免费看 | 99国产精品久久久久久久久久 | 成人久久视频 | 天天色中文 | 色综合久久中文字幕综合网 | 永久免费在线 | 欧美专区国产专区 | 狠狠色噜噜狠狠狠狠2022 | 手机看国产毛片 | 日韩中文字幕第一页 | 国产免费亚洲高清 | 欧美日韩网站 | 久久精品一区八戒影视 | 日韩久久激情 | 青青河边草免费直播 | 亚洲aⅴ一区二区三区 | 欧美亚洲国产精品久久高清浪潮 | 在线 精品 国产 | 免费看wwwwwwwwwww的视频 久久久久久99精品 91中文字幕视频 | 精品亚洲欧美一区 | 久久久香蕉视频 | 日韩中字在线 | 韩国av永久免费 | 最近2019年日本中文免费字幕 | 麻豆一区二区三区视频 | 久久精品国产成人精品 | 午夜av大片| 久草在线视频网站 | 久久免费公开视频 | 一区二区在线不卡 | 亚洲精品综合在线 | 亚洲成成品网站 | 日韩高清在线一区二区 | 日韩激情久久 | 91在线中字 | 久久综合日 | 久热久草在线 | 99精品在线观看 | 91.dizhi永久地址最新 | 亚洲欧洲成人精品av97 | 久99久精品 | 国产成本人视频在线观看 | 国产小视频在线播放 | 天天爱天天射 | 精品国产乱码久久久久久浪潮 | 91精品国产三级a在线观看 | 五月天婷亚洲天综合网鲁鲁鲁 | 欧美精品久久久久久久久久白贞 | 日韩v欧美v日本v亚洲v国产v | 97视频资源 | 日韩国产精品一区 | 国产一级特黄电影 | 亚洲精品久久久蜜桃直播 | 成人免费视频视频在线观看 免费 | 国产v在线播放 | 国内精品久久久久久久久久久 | 久草网站在线观看 | 久久精品xxx | 99re视频在线观看 | 一区二区三区免费看 | 国产男女无遮挡猛进猛出在线观看 | 欧美精品久| 天堂av网站| 九九热在线精品视频 | 99精品视频一区二区 | 欧美日韩国产页 | 久久高清av | 亚洲人xxx| 国产成人三级在线观看 | 国产午夜一级毛片 | 中文字幕免费在线 | 91综合视频在线观看 | 五月婷影院 | 欧美国产日韩在线观看 | 91视频最新网址 | 特级西西www44高清大胆图片 | 国产精品精品国产色婷婷 | 午夜在线观看 | 久久久久久久久久久久久9999 | 国产日韩亚洲 | 午夜精品福利在线 | 国产97碰免费视频 | h视频日本 | 国产免费精彩视频 | 婷婷激情欧美 | 尤物九九久久国产精品的分类 | 不卡电影免费在线播放一区 | 五月开心激情网 | 欧美日韩免费在线观看视频 | 日本精品一区二区在线观看 | 人人干人人做 | 中文字幕视频免费观看 | 国产精品美女在线观看 | 伊色综合久久之综合久久 | 久热色超碰| 亚洲国产欧美在线看片xxoo | 天天操天天干天天操天天干 | av片中文字幕 | 国语精品免费视频 | 在线看小早川怜子av | 97精品国产97久久久久久久久久久久 | 日韩欧美国产激情在线播放 | 91桃色免费视频 | 69av视频在线 | 免费观看黄色12片一级视频 | 一区二区三区四区影院 | 91系列在线 | 亚洲成年人免费网站 | 狠狠色丁香婷婷综合最新地址 | 日韩在线精品一区 | 一区二三国产 | 久久久久久久网 | 成人三级av | av九九| a天堂最新版中文在线地址 久久99久久精品国产 | 欧美日韩国产一二 | 人人爽人人做 | 一级免费片 | 免费日韩电影 | 国产黄色资源 | 国产无限资源在线观看 | 国产1区2区 | 欧美在线日韩在线 | 国产精品久久久久影院日本 | 四虎国产精 | 91麻豆视频 | 成人av电影在线观看 | av片在线看 | 国产精品一区二区久久精品 | 97日日 | 大荫蒂欧美视频另类xxxx | 久久人人爽人人爽人人片 | 久久精品视频播放 | 日韩午夜三级 | 亚洲精品资源 | 国产一二区精品 | 中文字幕在线播放第一页 | 免费国产视频 | 字幕网av | 亚洲精品黄色 | 日韩精品久久一区二区三区 | 亚洲欧美视频 | 国产精品欧美 | 91成品人影院 | 黄色片免费看 | 亚洲国产精品va在线看 | 久久理论电影 | 国产xxxx | 日韩首页 | 午夜三级福利 | 一区二区视频电影在线观看 | 999视频在线观看 | 日韩簧片在线观看 | 国产精品99久久久久的智能播放 | 丁香视频免费观看 | 成年人免费在线观看网站 | 99re6热在线精品视频 | 亚洲欧洲精品一区二区精品久久久 | 久久久精品国产一区二区电影四季 | 91| av一区二区在线观看中文字幕 | 国产99免费视频 | 国产精品中文字幕在线 | 麻豆视频在线 | 成人h在线播放 | 99精品国产99久久久久久福利 | 久久久久在线 | 欧美日韩xxxxx | 啪啪免费观看网站 | av不卡免费在线观看 | 亚洲欧洲中文日韩久久av乱码 | 99热最新精品 | 天天摸天天操天天舔 | 国产精品免费看久久久8精臀av | 亚洲视频在线视频 | 久久精品国产亚洲 | 国产精品毛片久久久久久久久久99999999 | 99热这里| 日韩午夜电影网 | 8x8x在线观看视频 | 97超碰超碰久久福利超碰 | 天天干天天操天天入 | 午夜国产成人 | 欧美一级久久久久 | 欧美三级在线播放 | 国产午夜三级一区二区三桃花影视 | 久久精品网站视频 | 久久tv视频 | 欧美在线视频a | 精品在线视频播放 | 97电影院在线观看 | 国产在线v| 欧美成人一区二区 | 精品国产三级a∨在线欧美 免费一级片在线观看 | 少妇性aaaaaaaaa视频 | 色综合久久精品 | 亚洲精品视频在线观看免费 | 99精品在线看 | 久久九九精品久久 | 高清国产午夜精品久久久久久 | 中文字幕激情 | 国产精品中文在线 | 天天爱天天操天天爽 | 久久精品国产亚洲 | 国偷自产中文字幕亚洲手机在线 | 欧美一级大片在线观看 | 亚洲视频综合在线 | 精品视频一区在线 | 久久国产午夜精品理论片最新版本 | 日韩美一区二区三区 | 在线观看精品黄av片免费 | 97在线免费视频 | 成年人黄色免费看 | 91大神电影 | 久久精品久久久久久久 | 伊人五月天 | 国产一区在线精品 | 丁香花五月 | 在线综合 亚洲 欧美在线视频 | 久久激情视频免费观看 | av电影中文字幕在线观看 | 天天天天射 | 日韩电影一区二区在线 | 国产韩国精品一区二区三区 | 亚洲国产中文在线观看 | 九九热视频在线播放 | 激情综合网天天干 | 亚洲精品日韩在线观看 | 色综合夜色一区 | 天天干天天摸 | 日本精品视频免费观看 | av免费网 | 久久久久成人精品免费播放动漫 | 狠狠久久婷婷 | 99日精品| 天天爽人人爽 | 国产精品久久久久久久av大片 | 激情综合狠狠 | 91香蕉亚洲精品 | 国产视频一二区 | 欧美一级乱黄 | 日韩99热 | 欧美大片aaa | 亚州精品天堂中文字幕 | 五月天激情电影 | 99在线免费视频 | 91成人在线看 | 一区二区中文字幕在线观看 | 片黄色毛片黄色毛片 | 免费看久久 | 国产91综合一区在线观看 | 99在线热播精品免费 | 日本精品中文字幕在线观看 | 亚洲精品一区二区网址 | 三级av小说 | 免费看的国产视频网站 | 又色又爽又黄 | 97在线看| 日日爱网址 | 午夜av免费 | 97视频免费在线看 | 精品福利av | 天天爱av导航 | 色吊丝av中文字幕 | av成人动漫在线观看 | 夜夜骑日日操 | 91成人免费在线视频 | 91精品国产九九九久久久亚洲 | 中文字幕之中文字幕 | 免费看在线看www777 | 免费网站黄 | 国产精品xxxx18a99| 国产成人精品久 | 韩日视频在线 | av免费在线免费观看 | 免费视频久久久久久久 | 91女人18片女毛片60分钟 | 日韩av一区二区在线播放 | 日韩欧美精品在线观看 | 国产精品自产拍在线观看桃花 | 欧美一二三四在线 | 成年人免费在线观看网站 | 乱男乱女www7788 | 国产艹b视频| 久久影院中文字幕 | 丁香六月婷婷激情 | 日韩视频一区二区三区在线播放免费观看 | 91麻豆传媒| 久视频在线播放 | a色视频 | 日本中文字幕电影在线免费观看 | 国产中文字幕视频在线观看 | 亚洲欧美视频 | 日韩黄色在线观看 | 大荫蒂欧美视频另类xxxx | 亚洲国产高清在线观看视频 | 久久久精品视频网站 | 又色又爽又黄 | 久草视频在线资源站 | 亚洲专区在线视频 | 国产人免费人成免费视频 | www好男人 | 亚洲成人一二三 | 日韩欧美一二三 | 色偷偷av男人天堂 | 日韩激情免费视频 | 天天操天天操天天 | 欧美日韩国产页 | 成人一级电影在线观看 | 在线成人小视频 | 天天干天天做天天爱 | 亚洲精品高清在线 | 亚洲欧美在线观看视频 | 日韩欧美精品一区二区 | 免费在线激情视频 | 97超级碰| 国产精品孕妇 | 九九在线高清精品视频 | 色婷婷五| 国产999精品久久久久久麻豆 | 亚洲精品中文在线观看 | 黄色精品久久久 | 欧美专区日韩专区 | 日韩在线高清免费视频 | 91精品爽啪蜜夜国产在线播放 | 在线超碰av | 国产裸体bbb视频 | 探花系列在线 | 国产视频精品免费 | 成人性生活大片 | 91中文在线观看 | 亚洲精品久久久久久国 | 午夜久久影院 | 日韩动漫免费观看高清完整版在线观看 | 成全免费观看视频 | 久久久亚洲网站 | 国产精品自拍在线 | 国产在线观看你懂得 | 精品一二三区 | 国产精品嫩草影院99网站 | 99久久综合狠狠综合久久 | 国产精品午夜在线 | 中国一级片在线观看 | 天堂网av 在线 | 国产xxxx做受性欧美88 | 三级在线视频观看 | 色综合天天色综合 | 日韩在线观看网站 | 亚洲激情小视频 | 日日爱网址 | 五月婷婷天堂 | av888.com| 国产日韩欧美中文 | 精品久久网 | 亚洲国产午夜视频 | 国产香蕉久久精品综合网 | 日韩欧美视频一区 | 国产精品久久久久久久久久久免费看 | 国产一区二区三区免费在线观看 | 五月天天在线 | 人人射 | 日韩经典一区二区三区 | 一 级 黄 色 片免费看的 | 日韩xxxbbb| 久久精品在线免费观看 | 黄色一级片视频 | 日韩精品国产一区 | 欧美va天堂在线电影 | 免费视频久久久 | 最新久久免费视频 | 中文字幕色站 | 国产福利av在线 | 天堂资源在线观看视频 | 日韩久久一区 | 久草在线最新视频 | 日韩色视频在线观看 | 97国产超碰 | 久久99国产综合精品免费 | 午夜丁香视频在线观看 | 中文字幕欧美日韩va免费视频 | 日韩成人av在线 | 97成人精品视频在线播放 | 五月婷婷激情综合 | 黄色av高清| 麻豆成人在线观看 | 97超碰人人 | 午夜精品av | 日韩高清免费无专码区 | 婷婷在线精品视频 | 欧美a影视| 亚州性色 | 四虎永久国产精品 | 五月婷婷综合在线视频 | 免费99视频 | 国产精品破处视频 | 欧美色就是色 | 国产剧情在线一区 | 国产精品嫩草69影院 | 久久99精品久久久久久三级 | 91精品1区2区| 人人盈棋牌 | 亚洲欧美日韩一区二区三区在线观看 | 亚洲视频999| 国产精品一二三 | 在线一区av | 国产欧美久久久精品影院 | 日日夜夜噜 | 成人av资源 | 日b视频国产 | 亚洲国产精品一区二区尤物区 | 24小时日本在线www免费的 | 精品国产成人在线影院 | 国产成人精品亚洲精品 | 最近能播放的中文字幕 | 久久国产亚洲精品 | 久久婷婷国产色一区二区三区 | 青草视频在线免费 | 国产69精品久久久久9999apgf | 国产黄色精品在线 | 六月久久婷婷 | 亚洲精品中文在线观看 | 日韩av片无码一区二区不卡电影 | 免费看片成年人 | 久久免费视频观看 | 97精品国产 | 91视频免费网址 | 亚洲视频一区二区三区在线观看 | 激情婷婷在线 | 亚洲激情av | 啪啪精品 | 最新动作电影 | 男女激情免费网站 | 波多野结衣在线播放视频 | 日韩欧美综合在线视频 | 成人污视频在线观看 | 国产精品久久久久aaaa九色 | 四虎8848免费高清在线观看 | 激情五月婷婷综合 | 91精品国产91久久久久久三级 | 日本久热 | av免费看网站 | 国产中文字幕在线播放 | 日韩电影在线观看一区 | 精品毛片在线 | 99久久激情视频 | 99视频在线免费 | 九九热精品在线 | 国产日韩中文在线 | 九九在线免费视频 | 日韩av电影中文字幕在线观看 | 激情在线网址 | 综合婷婷 | 97视频中文字幕 | 日韩理论片中文字幕 | 午夜视频色 | avhd高清在线谜片 | 精品国产欧美一区二区 | 午夜久操 | 波多野结衣久久精品 | 久久99久久99精品免视看婷婷 | 特级西西人体444是什么意思 | 97在线免费视频 | 美女福利视频网 | 欧美日韩国产在线 | 国产精品久久久久三级 | 日韩精品一区二区在线视频 | 国产成人精品国内自产拍免费看 | 婷婷激情欧美 | 国内外成人在线 | 狠狠五月婷婷 | 91桃花视频| 欧美日韩国产三级 | 视频一区二区在线 | 久久电影国产免费久久电影 | 五月婷婷在线视频 | 色爱区综合激月婷婷 | 成人毛片一区二区三区 | 国产字幕在线播放 | 欧美在线观看视频 | 精品久久久久久久久久久久 | 九九热免费在线观看 | 在线视频观看成人 | 色视频网站免费观看 | 一级黄色av| 97超碰中文 | 久久影院中文字幕 | 国产精品久久二区 | 手机看国产毛片 | 久久亚洲私人国产精品va | 又色又爽又黄高潮的免费视频 | 婷婷色吧 | 人人看人人做人人澡 | 在线精品一区二区 | 日韩v在线91成人自拍 | 久久久香蕉视频 | 黄色亚洲大片免费在线观看 | 中文字幕在线观看你懂的 | 日韩小视频 | 亚洲国产成人av网 | av一级网站 | 中文字幕不卡在线88 | 亚洲一二三区精品 | 亚洲五月六月 | 午夜美女福利直播 | 视频一区二区精品 | 五月天中文在线 | 成人欧美在线 | 久久一区国产 | 黄色视屏在线免费观看 | 久久久久麻豆v国产 | 91经典在线| 日韩av中文字幕在线 | 日韩二区三区在线观看 | 久草观看视频 | 婷婷av综合 | 黄色片软件网站 | 99热手机在线观看 | 亚洲精品ww| 综合网av | 久久精品麻豆 | 婷婷综合亚洲 | 五月天婷亚洲天综合网鲁鲁鲁 | 欧美性高跟鞋xxxxhd | 日韩欧美视频一区二区三区 | 久久精品91久久久久久再现 | a级片久久| 国产午夜精品一区二区三区嫩草 | 狠狠色综合网站久久久久久久 | 国产啊v在线 | 中文字幕在线观看视频免费 | 亚洲国产免费网站 | www亚洲视频| 在线国产精品一区 | 天天爽天天摸 | 亚洲精区二区三区四区麻豆 | 亚洲一区二区精品3399 | 六月丁香在线观看 | 国产精品1024 | 国产一区免费在线 | 日韩成人免费电影 | 亚洲国产中文在线观看 | 日本成人黄色片 | 婷婷丁香激情综合 | 天天综合网久久综合网 | 国产黄色片网站 | 免费高清在线视频一区· | 99re亚洲国产精品 | 久久成人18免费网站 | 婷婷在线视频 | 久久精品看片 | 夜夜操狠狠干 | 国产xxxx性hd极品 | 在线观看国产区 | 亚洲成人av电影在线 | 日韩 在线观看 | 色五月成人 | 成人在线视频在线观看 | 久久久免费 | 午夜 在线 | 国产日韩精品在线 | 九九久久成人 | 黄色毛片一级片 | 久久理论影院 | 国产精品不卡 | 在线播放你懂 | 一级黄色大片在线观看 | 99在线观看 | 精品二区久久 | 日韩av一区二区在线影视 | 欧美一区二区伦理片 | 99久热在线精品视频成人一区 | 一区二区视频播放 | 91在线免费观看国产 | 中文字幕国产在线 | 欧美人牲 | 黄色日批网站 | 天天干天天拍天天操 | 97超碰人人澡人人爱学生 | 一区二区欧美在线观看 | 成人黄色电影在线观看 | 亚洲全部视频 | 国产精品自产拍在线观看中文 | 亚洲婷婷丁香 | 一本色道久久综合亚洲二区三区 | 五月香视频在线观看 | 狠狠操狠狠干天天操 | 午夜av大片 | 天天操夜夜逼 | 日韩亚洲国产精品 | 日韩精品一区二区三区外面 | 四川妇女搡bbbb搡bbbb搡 | 怡红院成人在线 | 日韩av成人在线观看 | 99久久99久久精品 | 国产在线观看91 | 亚洲高清视频一区二区三区 | 久久伊人免费视频 | 狠狠色丁香久久婷婷综 | 国产伦理精品一区二区 | 狠狠色伊人亚洲综合网站野外 | 久艹在线免费观看 | 国产精品美女久久久久aⅴ 干干夜夜 | 日本公妇在线观看高清 | 中文字幕资源网 国产 | 久久亚洲国产精品 | 免费视频久久久 | 亚洲九九九在线观看 | 欧美不卡视频在线 | 国产a级精品 | 一区二区三区中文字幕在线 | 中文字幕丰满人伦在线 | 免费成人av | 高清在线一区 | 国产明星视频三级a三级点| 黄色aa久久 | 久草在线高清视频 | 一级久久精品 | 国产 日韩 欧美 中文 在线播放 | 久久亚洲精品电影 | 97精产国品一二三产区在线 | 中文字幕黄色av | 在线观看精品 | 中文字幕av专区 | 免费国产在线视频 | 一级a性色生活片久久毛片波多野 | 久久精品国产精品亚洲精品 | 精品久久一区二区 | 久精品视频 | 欧美精品乱码久久久久久按摩 | 91成年人网站 | 女女av在线 | 国产午夜三级 | 91亚州 | www.国产毛片| 日本xxxx裸体xxxx17 | 超碰人人在线 | 一级黄色a视频 | 又黄又爽又刺激视频 | 黄色免费国产 | 久久精品视频国产 | 亚洲国产中文字幕在线观看 | 最新91在线视频 | 美女视频黄,久久 | 射射射综合网 | 亚洲精品av在线 | 欧美男男激情videos | 久久久久免费精品国产小说色大师 | 高清一区二区三区 | 国产亚洲精品久久久久久久久久久久 | 久久伊人免费视频 | 中文字幕 国产 一区 | 国产福利专区 | 五月天丁香综合 | 国精产品永久999 | 国内综合精品午夜久久资源 | 婷婷国产在线观看 | 欧美日本日韩aⅴ在线视频 插插插色综合 | 一区免费观看 | av在线最新 | 综合色婷婷 | 91免费版在线 | 久久精品中文视频 | www.色爱| 久久99精品国产99久久6尤 | 色网址99| 精品少妇一区二区三区在线 | 男女日麻批| 99精品久久只有精品 | 精品影院一区二区久久久 | 91精品国产成人 | 久久激情片| 免费日韩一级片 | 日日综合网 | 韩日精品在线观看 | 免费大片av| 伊人一级| 99久久综合狠狠综合久久 | 日韩在线视频网 | 成人黄色电影在线播放 | 国产小视频在线播放 | 国产精品久久久影视 |