HashMap
HashMap底层其实是一个存放链表的数组,底层存的是一个Entry对象
Entry对象包含
K - 键,
V - 值,
next 下一个Entry对象的引用
当你往HashMap中存放元素时,HashMap会先通过hashcode()方法算出元素的hashcode值,然后通过hashcode值算出其应该存在数组的哪个下标处。(通过移位计算出下标)
如果数组的该下标处已经存放了元素,并且已存放的元素和你正在放的元素不相同的话,那么就会将你正在放的这个元素加到数组该下标存的链表的末端,如果相同的话,会把旧的元素返回,用新的元素覆盖旧的元素。
那么,随着你放的元素数量越多,你的链表自然而然的就会越长,这样存取效率就会变得很低。
hashmap底层规定,当元素数量超过了 (容量 * 负载因子)的话,hashmap会将数组扩容,既将容量变为原来的两倍
注: HashMap 初始容量为16 负载因子为0.75
HashMap的容量总是会为2的n次方倍。这样就可以通过hashcode移位运算得出元素应该存在哪个下标()
,不用通过取模运算,
具体计算方式为hashcode & (table.length -1)
扩容后要重新计算每个元素在数组中的位置,而这是一个非常消耗性能的操作,所以如果我们已经预知 HashMap 中元素的个数,那么预设元素的个数能够有效的提高 HashMap 的性能。
所以,我们初始化HashMap时要尽可能的指定HashMap的初始容量
(注意:hshcode()方法必须保证相同元素的hashcode值必须相同,不同元素的hashcode值尽量不同)
HashSet
HashSet底层仍然是HashMap,
只不过HashSet是将元素存在了底层HashMap的key中,而底层HashMap的value使用一个static final的Object对象标识
那么HashSet是怎么保证其中不允许有重复元素的呢,既如果HashSet中存储了这个元素,当你再往HashSet里面放这个元素的时候,HashSet的add方法就会返回false
原理:
底层的HashMap会通过hashcode()和equals()方法来判断两个元素是否相同,如果相同的话,会用新的元素替代旧的元素(但其实这两个元素是相同的,替代了以后还是原来那个元素)。这样就保证了HashSet中元素的不重复性。
注意:使用HashMap和HashSet时必须保证相同元素的hashcode()返回值相等,并且equals()方法返回true;'