集合類總結

2022-09-19 00:39:07 字數 4038 閱讀 3199

可分為單列集合和雙列集合,即collection介面(單列)和map介面(雙列,即key-value集合)

集合體現了多型的思想。

主要方法:

1.arraylist類

since v1.2,底層是陣列,預設容量10

特點:效率較高,但是執行緒不安全

擴容機制:無參構造方法會先建立初始10容量的物件陣列elementdata,之後擴容會變成原來的1.5倍

2.vector類

since v1.0,底層是陣列。

特點:效率低,但是執行緒安全(方法裡都寫了synchronized)

擴容機制:底層也是elementdata的物件陣列,初始容量10,之後每次擴容會變成原來兩倍(個人理解為多執行緒時才需要synchronized,所以往往會需要比較大的容量,如果擴容小了會頻繁的進行擴容);

linkedlist類

since v1.2,底層是雙向鍊錶

特點:執行緒不安全,方便增刪,不方便改查

特點:1.hashset類

底層是hashmap,只是value值用常量object物件present佔位了,實際儲存的資料就是key。

2.linkedhashset類

是hashset的子類,底層linkedhashmap,是陣列+雙向鍊錶的資料結構

特點:有序(使用雙向鍊錶可以進行按照存入順序取出)

陣列是hashmapnode型別的,但是存放的元素是linkedhashmap entry型別的,entry類是node類的子類。這是多型現象。

3.treeset類

底層為treemap。

特點:可以進行排序

新增的元素必須實現comparable介面(string類已經實現)。如果沒有實現該介面,則每次使用必須傳入乙個comparator

根據comparator的比較規則,追溯到底層,如果o1-o2==0的情況,那麼會進入setvalue方法,只是修改value值而不會新增新元素。例子:把comparator方法寫成str.length的比較,則相同長度的字串是無法重複新增的。

底層:陣列+鍊錶+紅黑樹,預設容量16

特點:key、value都可以有乙個null

key不可重複,value可以

擴容機制

當某條鏈上節點超過8個(此時bigcount=7,node=9個,bigcount>=default(8)-1)時會進行樹化判斷,此時如果陣列大小沒到64會進行擴容,也就是說node=9時,resize1次,capacity=32,node=10時,capacity=64,node=11時,進行樹化。

如果鏈上的節點都沒有超過8個,那麼會判斷是否到達臨界值,由載入因子決定臨界值:threshold=0.75*當前容量。第一次的時候threshold=0.75 *16=12,當新增了第13個節點後進行擴容,16 *2 =32;

常見問題

1.hashmap的hash()方法不是得到hashcode值,而是得到hashcode優化後的值:(h = key.hashcode()) ^ (h >>> 16)

它會先用這個key值求出hashcode值並賦給h,然後用這個hashcode值與無符號右移16位後的hashcode進行異或操作(相同的為0,不同的為1,0異或任何都等於它本身,1異或任何都等於它求反),這樣做可以減少碰撞率。

static inline intptr_t get_next_hash(thread * self, oop obj)  else

if (hashcode == 1) else

if (hashcode == 2) else

if (hashcode == 3) else

if (hashcode == 4) else

value &= markoopdesc::hash_mask;

if (value == 0) value = 0xbad ;

assert (value != markoopdesc::no_hash, "invariant") ;

tevent (hashcode: generate) ;

return value;

}

由上述**可以知道,當全域性變數hashcode==4的時候,hashcode()的計算結果才是記憶體位址。

3.hashset類新增重複的元素,是被覆蓋還是不處理?

hashset的底層是hashmap,實際上它雖然是hashmap的結構,但是set集合是單列集合,即它只儲存key值,value值是乙個不可更改的static final object物件:present(只是佔坑用的,實際沒什麼作用)。當新增重複的元素的時候,key值是不會覆蓋的,雖然說hashmap的value值可以覆蓋,但這裡實際上替換的還是同乙個靜態物件present。

4.hashmap的entryset 、keyset、values之間的區別?

這三者都可以通過map的方法去獲得,如 set entryset = map.entryset();

區別1:values是collection型別的,而keyset、entryset是set型別的。keyset存放的只是key,而entryset實際存放的key是map.entry,它的實現類就是node。所以它這個key實際上包含了鍵和值的對映

區別2:遍歷速度,values是最快的,但沒有意義,主要比較keyset和entryset。可能會覺得keyset少了values會遍歷得更快,實際相反,entryset可以直接用方法getkey()、getvalue()獲取key-value值,並且他獲取entry的值也是通過先遍歷陣列(hash可以篩選大部分的元素)然後再遍歷少量的鍊錶元素即可。但是keyset方法只是獲取key值,然後再根據map.get(key)去求value值,並且set集合是單鏈表,查詢是比較麻煩的。

5.為什麼重寫了equals方法後還要重寫hashcode()方法?

重寫hashcode方法主要用在hashmap、hashset這類集合裡,如果不涉及hashcode的話其實沒必要重寫。重寫hashcode是由hashmap的底層機制決定的,他會先根據新增的key,通過hashcode後計算得到索引位置(p = tab[i = (n - 1) & hash]),如果索引位置衝突了,才會進行equals比較。如果不重寫hashcode方法,在判斷陣列索引這一步,如果hash值不一致,很有可能索引位置不會發生衝突,找個空的位置就直接加進去了,這不符合set和map的key值唯一的規則。

since 1.0,

1.和hashmap差別不是很大,主要是執行緒安不安全,以及是否可null 之類的

2.預設容量11,threshold=8;之後擴容按2n+1擴。

習題//person類已按照id、name重寫了hashcode和equals方法,以下幾個語句的輸出是?

hashset set = new hashset();

person p1 = new person(1001,"aa");

person p2= new person(1002,"bb");

set.add(p1);

set.add(p2);

p1.name="cc";

set.remove(p1);

system.out.println(set);

set.add(new person(1001,"cc"));

system.out.println(set);

set.add(new person(1001,"aa"));

system.out.println(set);

1.remove方法因為重寫了hashcode 和equals方法,hash索引變更,無法根據新的hash值找到存放的位置,刪除失敗;所以第乙個輸出仍為2;

2.1001,"cc"這個新物件雖然和修改後的p1一樣,但是p1仍存放在原來1001,「aa」索引的位置,所以1001,"cc"可以存放在空的索引位置,輸出3個了;

3.此時新物件1001,「aa」索引和p1一樣,但是因為equal方法重寫了,所以會掛在p1後面成煉表。

JAVA集合類總結

所有的集合類都是先iterator介面,意味著所有的集合類都是可以迭代輸出的。以collection為介面的元素集合型別,以map為介面的對映集合型別 所有集合的實現類都不是直接實現集合類介面,而是都繼承乙個相應的抽象類。list list介面提供了多個實現的子類,其實現類有arraylist,li...

Java集合類自己總結

以下是常用子介面 arraylist01 public class arraylistdemo01 arraylist02 public class arraylistdemo02 arraylist03 public class arraylistdemo03 system.out.print n...

java 集合類 7 總結

vector 用arraylist代替vector。hashtable 用hashmap代替hashtable。satck 用linkedlist代替stack。properties hashtable和hashmap的區別 1.hashtable是dictionary的子類,hashmap是map...