摘要:繼承的類,泛型為時(shí),注意和其他的類型不同。因?yàn)槭蔷€程安全簡(jiǎn)單來(lái)說(shuō),是個(gè)一維數(shù)組。同樣,指定和,如果中間發(fā)生變化則會(huì)拋出異常。最后,可以,然后,使用基類可以實(shí)現(xiàn)和的快速賦值。線程安全也是線程安全的,和一樣,連函數(shù)都喪心病狂地同步了。
這么幾個(gè)比較常用的但是比較容易混淆的概念同出于 java.util 包。本文僅作幾個(gè)類的淺度解析。
(本文基于JDK1.7,源碼來(lái)自openjdk1.7。)
├── Collection │?? ├── List │ │?? ├── ArrayList │?? │ ├── Vector │?? │ └── LinkedList and so on; │ Set │?? ├── HashSet │?? └── LinkedHashSet and so on; └── Map ?? ├── Hashtable ?? ├── HashMap ?? └── WeakHashMap and so on;Collection和Map
按理來(lái)說(shuō)和這兩者沒(méi)有什么特別關(guān)系。然而本文中仍然將這兩個(gè)混在一起:
第一,HashSet,HashMap,Hashtable長(zhǎng)得太像了,沒(méi)有理由不寫(xiě)再一起。
第二,HashSet是個(gè)Set,其實(shí)骨子里是個(gè)Map。
List繼承List的類,泛型為Integer時(shí),注意和其他的類型不同。(因?yàn)镮ndex是Integer)
線程安全簡(jiǎn)單來(lái)說(shuō),List是個(gè)一維數(shù)組。Vector和ArrayList區(qū)別在于:
Vector是個(gè)線程安全的,而ArrayList不是。這點(diǎn)看源碼可以看出來(lái),Vector中各種synchronized,甚至連size屬性都喪心病狂地synchronized了。
同樣,Iterator指定Vector和ArrayList,如果中間發(fā)生變化則會(huì)拋出ConcurrentModificationException異常。
不僅僅是List,很多地方的Iterator都有這個(gè)異常,
ArrayList沒(méi)辦法設(shè)置自增大小,但是仍然可以自增。
Vector可以設(shè)置自增大小。
ArrayList的自增函數(shù):
Vector的自增函數(shù):
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); //在這里,如果沒(méi)有設(shè)置自增大小的話,那么默認(rèn)自增大小則是原來(lái)的Vector大小。 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); elementData = Arrays.copyOf(elementData, newCapacity); }
ArrayList自增函數(shù):
private void grow(int minCapacity) { // overflow-conscious code int oldCapacity = elementData.length; int newCapacity = oldCapacity + (oldCapacity >> 1); //新長(zhǎng)度則是舊長(zhǎng)度的大小加上一個(gè)移位運(yùn)算(一半的大?。?。 if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); // minCapacity is usually close to size, so this is a win: elementData = Arrays.copyOf(elementData, newCapacity); }
所以可以簡(jiǎn)單的認(rèn)為Vector默認(rèn)自增一倍的長(zhǎng)度,ArrayList則是默認(rèn)自增一半的長(zhǎng)度。
同樣,對(duì)他們的源碼分析:
Vector可以設(shè)置自增大小,而ArrayList則無(wú)法設(shè)置(沒(méi)有這個(gè)構(gòu)造方法)。
public Vector(int initialCapacity, int capacityIncrement)
最后,可以 List list=new ArrayList<>();,然后list=new Vector<>();,使用基類List可以實(shí)現(xiàn)ArrayList和Vector的快速賦值。
MapMap可以當(dāng)成是簡(jiǎn)單的“Key-Value”數(shù)據(jù)庫(kù),例如memcached和redis。
線程安全Hashtable基于Directory,有種說(shuō)法是Directory已經(jīng)過(guò)時(shí),所以更推薦使用Map。
Hashtable也是線程安全的,和Vector一樣,連size函數(shù)都喪心病狂地同步了。
public synchronized int size() { return count; }
HashMap不是線程安全的,當(dāng)然也可以用其他的黑科技實(shí)現(xiàn)同步,例如SynchronizedMap和ConcurrentHashMap。
那個(gè)以后再說(shuō)……
HashMap允許在Key和Value中都出現(xiàn)null值。例如:
v.toString() {null=null, 1=66, 2=null, 3=4d, 4=0f, 5=null}
而Hashtable則不允許K/V的任何一個(gè)出現(xiàn)null值,但是允許空字符串。
Hashtablev=new Hashtable (); v.put("3s",null);
直接報(bào)錯(cuò):java.lang.NullPointerException。
這個(gè)和內(nèi)部實(shí)現(xiàn)有關(guān),Hashtable需要用到hashCode,所以必須要確保K/V不為null。
相關(guān)代碼寫(xiě)死在源碼里:
public synchronized V put(K key, V value) { // Make sure the value is not null if (value == null) { throw new NullPointerException(); } //下面對(duì)hashCode做點(diǎn)事情。Set
HashSet本質(zhì)上是一個(gè)Collection,類似于List,是列表/集合,不是K-V的Map,但是它骨子里是一個(gè)HashMap……
這么說(shuō)可能會(huì)更易于理解:
HashSet對(duì)外是“類”的集合,實(shí)際上是內(nèi)部維護(hù)了一個(gè)HashMap進(jìn)行實(shí)現(xiàn)。
實(shí)際上存儲(chǔ)的是兩個(gè):hashCode和類本身(字符串/自定義類等)。
HashSet進(jìn)行add的時(shí)候,會(huì)先進(jìn)行驗(yàn)證hashCode:
(HashSet進(jìn)行add操作實(shí)際上是對(duì)Map的put操作)
public V put(K key, V value) { if (table == EMPTY_TABLE) { inflateTable(threshold); } if (key == null) return putForNullKey(value); int hash = hash(key);//本函數(shù)里有hashCode int i = indexFor(hash, table.length); for (Entry一個(gè)對(duì)HashSet的自定義類的操作:e = table[i]; e != null; e = e.next) { Object k; if (e.hash == hash && ((k = e.key) == key || key.equals(k))) { V oldValue = e.value; e.value = value; e.recordAccess(this); return oldValue; } } modCount++; addEntry(hash, key, value, i); return null; }
class Name { private String first; private String last; public Name(String first, String last) { this.first = first; this.last = last; } public boolean equals(Object o) { if (this == o) { return true; } if (o.getClass() == Name.class) { Name n = (Name)o; return n.first.equals(first) && n.last.equals(last); } return false; } } public class HashSetTest { public static void main(String[] args) { Sets = new HashSet (); s.add(new Name("abc", "123")); System.out.println( s.contains(new Name("abc", "123"))); } }
代碼來(lái)自java中HashSet詳解
粗看上去是會(huì)返回true的,實(shí)際返回false。因?yàn)?HashSet 判斷兩個(gè)對(duì)象相等的標(biāo)準(zhǔn)除了要求通過(guò) equals() 方法比較返回 true 之外,還要求兩個(gè)對(duì)象的 hashCode() 返回值相等。而上面程序沒(méi)有重寫(xiě) Name 類的 hashCode() 方法,兩個(gè) Name 對(duì)象的 hashCode() 返回值并不相同,因此 HashSet 會(huì)把它們當(dāng)成 2 個(gè)對(duì)象處理,因此程序返回 false。如果想返回true,需要重寫(xiě)equals方法和hashCode方法。
集合操作至于hashCode,就是另一篇文章才解釋得清的了。
Set其實(shí)做集合操作更加簡(jiǎn)單。例如:
import java.util.*; public class SetOperation { public static void main(String[] args) { Setresult = new HashSet (); Set set1 = new HashSet (){{ add(1); add(3); add(5); }}; Set set2 = new HashSet (){{ add(1); add(2); add(3); }}; result.clear(); result.addAll(set1); result.retainAll(set2); System.out.println("交集:"+result); result.clear(); result.addAll(set1); result.removeAll(set2); System.out.println("差集:"+result); result.clear(); result.addAll(set1); result.addAll(set2); System.out.println("并集:"+result); } }
輸出:
交集:[1, 3] 差集:[5] 并集:[1, 2, 3, 5]參考文檔
hashSet中的equals方法和hashCode方法
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/64382.html
摘要:概述集合類主要有大分支,及。不能保證元素的排列順序,順序有可能發(fā)生變化不是同步的集合元素可以是但只能放入一個(gè)是接口的唯一實(shí)現(xiàn)類,可以確保集合元素處于排序狀態(tài)。如果這兩個(gè)的通過(guò)比較返回,新添加的將覆蓋集合中原有的,但不會(huì)覆蓋。 概述 Java集合類主要有2大分支,Collection及Map。Collection體系如下: https://upload-images.jianshu......
摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。有序,唯一紅黑樹(shù)自平衡的排序二叉樹(shù)。 本文是最最最常見(jiàn)Java面試題總結(jié)系列第三周的文章。主要內(nèi)容: Arraylist 與 LinkedList 異同 ArrayList 與 Vector 區(qū)別 HashMap的底層...
摘要:是哈希表實(shí)現(xiàn)的,中的數(shù)據(jù)是無(wú)序的,可以放入,但只能放入一個(gè),兩者中的值都不能重復(fù),就如數(shù)據(jù)庫(kù)中唯一約束。四和的相同點(diǎn)和區(qū)別相同兩者都是基于哈希表實(shí)現(xiàn)的內(nèi)部也都是通過(guò)單鏈表解決沖突問(wèn)題同樣實(shí)現(xiàn)了序列化和克隆接口區(qū)別繼承的父類不同。 一.Arraylist與LinkedList有什么區(qū)別? 1、ArrayList是實(shí)現(xiàn)了基于動(dòng)態(tài)數(shù)組的數(shù)據(jù)結(jié)構(gòu),因?yàn)榈刂愤B續(xù),一旦數(shù)據(jù)存儲(chǔ)好了,查詢操作效率...
摘要:解決沖突開(kāi)放定址法拉鏈法表解決沖突開(kāi)放定址法再哈希法鏈地址法建立公共溢出區(qū)并發(fā)包中的線程安全的集合容器線程安全的,不允許為,默認(rèn)個(gè)的數(shù)組,每個(gè)中實(shí)現(xiàn)就是了,通過(guò)定位。基于數(shù)組,線程安全的集合類,容量可以限制。 List List?元素是有序的、可重復(fù),實(shí)現(xiàn)List接口的集合主要有:ArrayList、LinkedList、Vector、Stack。 ArrayList:動(dòng)態(tài)數(shù)組...
閱讀 2328·2021-11-22 14:56
閱讀 1460·2021-09-24 09:47
閱讀 904·2019-08-26 18:37
閱讀 2818·2019-08-26 12:10
閱讀 1522·2019-08-26 11:55
閱讀 3140·2019-08-23 18:07
閱讀 2294·2019-08-23 14:08
閱讀 605·2019-08-23 12:12