java集合入門

2021-07-12 04:31:41 字數 2826 閱讀 7687

可重複,取出的順序與新增的順序一樣。

arraylist:採用變長陣列實現,內部使用陣列儲存新增的元素,如果元素的個數超過陣列的長度,則自動擴容。

linkedlist:內部採用雙向鍊錶實現。可以使用它模擬佇列、棧等資料結構。

不可重複,無序(取出的順序與新增的順序不一樣)

hashset:內部使用hashmap實現。其內部元素的排列順序以hashcode為準。

treeset:自己指定元素的排列順序。

儲存的是鍵值對。

hashmap:內部以雜湊鍊錶實現。

內部的資料結構為陣列+鍊錶,各個hash值相同的key的item以鍊錶形式儲存,而所有的鍊錶的頭節點又都儲存在乙個陣列中。以put為例,如下:

@override public v put(k key, v value) 

int hash = collections.secondaryhash(key);//獲取key的hashcode,當然內部進行了別的處理。處理主要目的是使key的hash值能分散的均勻些

hashmapentry tab = table;

int index = hash & (tab.length - 1);

for (hashmapentrye = tab[index]; e != null; e = e.next)

}// 沒有key的節點,那就新建乙個,並新增到節點中。

modcount++;

if (size++ > threshold)

addnewentry(key, value, hash, index);

return null;

}

最後一步的addnewentry是將新的key,value,hash構建成hashmapentry物件,然後插入到該鍊錶的表頭。

對於hashmapentry,它表示鍊錶的節點。對於鍊錶的節點來說,它至少有乙個指向於下乙個節點的指標(這也是為什麼需要將key,value重新封裝成hashmapentry物件的原因),並有儲存當前節點值的數值域。其成員變數如下:

final k key;

v value;

final int hash;

hashmapentrynext;

這是乙個很常規的鍊錶節點的資料結構。

由於使用了陣列儲存鍊錶的頭節點,所以當item過多時就需要進行擴容,否則會導致鍊錶越來越長,造成在查詢時對效能的消耗(鍊錶的查詢需要從頭節點乙個個的遍歷比對,不如陣列方便)。擴容的方法就是doublecapacity。如下:

private hashmapentry doublecapacity() 

int newcapacity = oldcapacity * 2;

hashmapentry newtable = maketable(newcapacity);//新建乙個容量為原來2倍的hashmapentry陣列

if (size == 0)

for (int j = 0; j < oldcapacity; j++)

int highbit = e.hash & oldcapacity;

hashmapentrybroken = null;

newtable[j | highbit] = e;//將舊陣列中的表頭移到新陣列中

for (hashmapentryn = e.next; n != null; e = n, n = n.next)

}if (broken != null)

broken.next = null;

}return newtable;

}

由於陣列進行了擴容,所以舊陣列中的節點的位置需要重新計算。相當於重構了整個map。

1,無論該map中是否存有資料,都必須有乙個陣列,對記憶體有一定的浪費。

2,需新建乙個物件,用於表示鍊錶中的節點。

3,不支援基本資料型別,使用int作為key時,必須轉換成integer,也是一種浪費。

4,擴容時必須重構map,還是浪費。

使用陣列+鍊錶結構,一方面利用了陣列的查詢方便的特性,另一方面又避免了陣列對記憶體的高要求——分配的空間必須是連續的。

對於大批量資料儲存時,使用hashmap是乙個不錯的選擇,最好能預估資料的大小,並且指定乙個初始容量。這種方法可以避免了hashmap的多次擴容,減少效能的消耗。

它是乙個變長陣列,內部含有指向資料首、尾元素的指標,類似於佇列——先進先出。

offer方法最終會執行到如下方法:

public void addlast(e e)
從這裡很容易看出,offer是將新元素新增到陣列的末尾,並根據需要判斷是否需要擴容。

而且由判斷條件可以知道,arraydeque實現的是迴圈佇列。之所以使用tail+1與陣列長度-1取&,是為了讓tail能迴圈著取陣列中的下標,從而達到迴圈佇列的目的。

再看一下pop方法:

public e removefirst() 

public e pollfirst()

其最終會走到這兩個方法,可以看出它只是從head中取乙個元素,然後判斷是否為null,如果是null就扔個異常。這是很簡單粗暴的,它沒有在取元素時

判斷當前

陣列中有沒有元素,但這種方式我喜歡——簡單直接,自己用的時候自己考慮這種事。

而且也節約乙個陣列空間——使用陣列實現迴圈佇列時,一般需要留一下位置不用,這樣才能判斷出當前陣列是沒有元素還是已經滿了。

當然,arraydeque也不需要判斷陣列是不是滿了,因為它會進行擴容。

無論是從offer還是pop中都可以看出,arraydeque不接收null元素。

java集合入門

集合 也叫作容器類 裝資料 物件 動態儲存多個物件 動態 容器的大小隨著儲存的物件的數量而改變 物件 引用型別 8種基本資料 包裝類型別 陣列 儲存相同資料型別的一組資料 1.泛型 集合 add object obj 子類型別 作用 保護集合中的資料的資料型別安全 2.遍歷集合 官配 迭代器 集合的...

java集合入門問題

問題 既然有了陣列,為什麼還要arraylist?答 因為陣列大小本來不可變 如果要變化,則必須重新分配記憶體,太消耗資源。陣列只能同一種基本資料型別 或者同乙個類的物件 排除object arraylist中有重複元素嗎?因為 增加值的順序是1,3,4,5,1,那麼輸出的的值順序為 考慮重複值和值...

Java集合 Map集合

map map 用於儲存具有對映關係的資料,因此 map 集合裡儲存著兩組值,一組值用於儲存 map 裡的 key,另外一組用於儲存 map 裡的 value map 中的 key 和 value 都可以是任何引用型別的資料 map 中的 key 不允許重複,即同乙個 map 物件的任何兩個 key...