摘要:從上往下看的源碼,標(biāo)注了路上一些景點(diǎn)。感興趣的同學(xué)可以繼續(xù)跟,它返回的是一個(gè)內(nèi)部實(shí)現(xiàn)的類實(shí)現(xiàn)了。此外,循環(huán)中的新舊數(shù)據(jù)遷移的行代碼也很經(jīng)典。一詞成功引起了筆者注意。與之對(duì)應(yīng)的是深拷貝。里面的對(duì)象會(huì)在原來(lái)的對(duì)象和它的副本之間共享。
從上往下看的源碼,標(biāo)注了路上一些“景點(diǎn)”。皮皮蝦,我們走。
/** * Constructs a new hashtable with the same mappings as the given * Map. The hashtable is created with an initial capacity sufficient to * hold the mappings in the given Map and a default load factor (0.75). * * @param t the map whose mappings are to be placed in this map. * @throws NullPointerException if the specified map is null. * @since 1.2 */ public Hashtable(Map extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }
initialCapacity不指定的話是默認(rèn)11;
這里多帶帶列出這個(gè)初始化方法,主要是因?yàn)檫@個(gè)2*t.size(),如果你還記得的話,在第二路文中介紹HashMap.resize()時(shí),它就是按2擴(kuò)容的。
/** * Returns an enumeration of the keys in this hashtable. * * @return an enumeration of the keys in this hashtable. * @see Enumeration * @see #elements() * @see #keySet() * @see Map */ public synchronized Enumerationkeys() { return this. getEnumeration(KEYS); } // Types of Enumerations/Iterations private static final int KEYS = 0; private static final int VALUES = 1; private static final int ENTRIES = 2;
看到synchronized想說(shuō)的是HashTable是同步,所以大多數(shù)方法都可見(jiàn)進(jìn)行了同步處理,這點(diǎn)與HashMap不同(其他差別:HashTable的key、value都不允許為null)。該方法通過(guò)Enumeration遍歷Hashtable的鍵(KEYS是定義的全局變量),類似的,還有通過(guò)Enumeration遍歷Hashtable的值。感興趣的同學(xué)可以繼續(xù)跟getEnumeration(),它返回的是一個(gè)hashtable內(nèi)部實(shí)現(xiàn)的Enumerator類(實(shí)現(xiàn)了Enumeration, Iterator)。
應(yīng)用實(shí)例如下:
Enumeration enu = table.keys(); while(enu.hasMoreElements()) { System.out.println(enu.nextElement()); }
/** * The maximum size of array to allocate. * Some VMs reserve some header words in an array. * Attempts to allocate larger arrays may result in * OutOfMemoryError: Requested array size exceeds VM limit */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
這里好奇的是“-8”從何而來(lái)?從stackoverflow得到的答案是(譯):
數(shù)組(ARRAY)需要用8bytes來(lái)存儲(chǔ)(2^31 = 2,147,483,648 )大小(size)。
/** * Increases the capacity of and internally reorganizes this * hashtable, in order to accommodate and access its entries more * efficiently. This method is called automatically when the * number of keys in the hashtable exceeds this hashtable"s capacity * and load factor. */ @SuppressWarnings("unchecked") protected void rehash() { int oldCapacity = table.length; Entry,?>[] oldMap = table; // overflow-conscious code int newCapacity = (oldCapacity << 1) + 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 (Entryold = (Entry )oldMap[i] ; old != null ; ) { Entry e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry )newMap[index]; newMap[index] = e; } } }
hashtable的新容量是:2倍+1,即始終為奇數(shù)。不同于前2回講過(guò)的hashmap中resize()則是2倍。why?我們知道“除2以外所有的素?cái)?shù)都是奇數(shù)”,而當(dāng)哈希表的大小為素?cái)?shù)時(shí),簡(jiǎn)單的取模哈希的結(jié)果分布更加均勻,從而降低哈希沖突。
“0x7FFFFFFF”即二進(jìn)制的32個(gè)1,按位與運(yùn)算后使得結(jié)果范圍在區(qū)間[0,2147483647]內(nèi),可以理解為取正。
此外,for循環(huán)中的新舊數(shù)據(jù)遷移的5行代碼也很經(jīng)典。
/** * Creates a shallow copy of this hashtable. All the structure of the * hashtable itself is copied, but the keys and values are not cloned. * This is a relatively expensive operation. * * @return a clone of the hashtable */ public synchronized Object clone() { try { Hashtable,?> t = (Hashtable,?>)super.clone(); t.table = new Entry,?>[table.length]; for (int i = table.length ; i-- > 0 ; ) { t.table[i] = (table[i] != null) ? (Entry,?>) table[i].clone() : null; } t.keySet = null; t.entrySet = null; t.values = null; t.modCount = 0; return t; } catch (CloneNotSupportedException e) { // this shouldn"t happen, since we are Cloneable throw new InternalError(e); } }
“shallow copy”一詞成功引起了筆者注意。what is it?淺拷貝非java獨(dú)有的概念,其他編程語(yǔ)言同樣存在,如C#、C++、IOS、python等。與之對(duì)應(yīng)的是深拷貝(deep copy)。兩者的區(qū)別是:
對(duì)象的淺拷貝會(huì)對(duì)“主”對(duì)象進(jìn)行拷貝,但不會(huì)復(fù)制主對(duì)象里面的對(duì)象。"里面的對(duì)象“會(huì)在原來(lái)的對(duì)象和它的副本之間共享。深拷貝是一個(gè)整個(gè)獨(dú)立的對(duì)象拷貝。[參考文獻(xiàn)2]
“I have a pen, I have a apple."(唱起來(lái)了) 我,筆,蘋(píng)果是三個(gè)對(duì)象,我引用了筆和蘋(píng)果,此時(shí)對(duì)我進(jìn)行拷貝,效果如圖:
public class Apple { String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } } Apple apple = new Apple(); apple.setColor("red"); Hashtable ht = new Hashtable(); ht.put("apple", apple); System.out.println(((Apple)ht.get("apple")).getColor()); Hashtable htc = (Hashtable) ht.clone(); System.out.println(((Apple)htc.get("apple")).getColor()); ((Apple)htc.get("apple")).setColor("green"); System.out.println(((Apple)ht.get("apple")).getColor()); System.out.println(((Apple)htc.get("apple")).getColor()); //輸出結(jié)果: //red //red //green //green //淺拷貝的hashtable共用一個(gè)蘋(píng)果
/** * Returns a string representation of this Hashtable object * in the form of a set of entries, enclosed in braces and separated * by the ASCII characters ", " (comma and space). Each * entry is rendered as the key, an equals sign =, and the * associated element, where the toString method is used to * convert the key and element to strings. * * @return a string representation of this hashtable */ public synchronized String toString() { int max = size() - 1; if (max == -1) return "{}"; StringBuilder sb = new StringBuilder(); Iterator> it = entrySet().iterator(); sb.append("{"); for (int i = 0; ; i++) { Map.Entry e = it.next(); K key = e.getKey(); V value = e.getValue(); sb.append(key == this ? "(this Map)" : key.toString()); sb.append("="); sb.append(value == this ? "(this Map)" : value.toString()); if (i == max) return sb.append("}").toString(); sb.append(", "); } }
"(this Map)",即,ht.put(ht, ht)將輸出{(this Map)=(this Map)}。
還有同步處理用到的volatile關(guān)鍵字(各個(gè)線程在訪問(wèn)該關(guān)鍵字所修飾變量前必須從主存(共享內(nèi)存)中讀取該變量的值)、Collections.synchronizedSet()(創(chuàng)建同步的集合對(duì)象)有緣再續(xù)。
更多有意思的內(nèi)容,歡迎訪問(wèn)筆者小站: rebey.cn
參考文獻(xiàn)[推薦]:1.HashMap和HashTable到底哪不同?,2016-07-05;
2.Java 中的淺拷貝與深拷貝(Shallow vs. Deep Copy in Java ),中英;
3.Java基礎(chǔ)之volatile關(guān)鍵字,2016-07-18;
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/67138.html
摘要:如今行至于此,當(dāng)觀賞一方。由于所返回的無(wú)執(zhí)行意義。源碼閱讀總體門(mén)檻相對(duì)而言比,畢竟大多數(shù)底層都由實(shí)現(xiàn)了。比心可通過(guò)這篇文章理解創(chuàng)建一個(gè)實(shí)例過(guò)程圖工作原理往期線路回顧源碼一帶一路系列之源碼一帶一路系列之源碼一帶一路系列之 本文以jdk1.8中LinkedHashMap.afterNodeAccess()方法為切入點(diǎn),分析其中難理解、有價(jià)值的源碼片段(類似源碼查看是ctrl+鼠標(biāo)左鍵的過(guò)程...
摘要:一路至此,風(fēng)景過(guò)半。與雖然名字各異,源碼實(shí)現(xiàn)基本相同,除了增加了線程安全。同時(shí)注意溢出情況處理。同時(shí)增加了考慮并發(fā)問(wèn)題。此外,源碼中出現(xiàn)了大量泛型如。允許為非線程安全有序。 一路至此,風(fēng)景過(guò)半。ArrayList與Vector雖然名字各異,源碼實(shí)現(xiàn)基本相同,除了Vector增加了線程安全。所以作者建議我們?cè)诓恍枰€程安全的情況下盡量使用ArrayList。下面看看在ArrayList源...
摘要:同樣在源碼的與分別見(jiàn)看到老朋友和。這樣做可以降低性能消耗的同時(shí),還可以減少序列化字節(jié)流的大小,從而減少網(wǎng)絡(luò)開(kāi)銷框架中。使用了反射來(lái)尋找是否聲明了這兩個(gè)方法。十進(jìn)制和,通過(guò)返回值能反應(yīng)當(dāng)前狀態(tài)。 Map篇暫告段落,卻并非離我們而去。這不在本篇中你就能經(jīng)常見(jiàn)到她。HashSet、LinkedHashSet、TreeSet各自基于對(duì)應(yīng)Map實(shí)現(xiàn),各自源碼內(nèi)容較少,因此歸納為一篇。 HashS...
摘要:本篇涉及少許以下簡(jiǎn)稱新特性,請(qǐng)?bào)H友們系好安全帶,準(zhǔn)備開(kāi)車。觀光線路圖是在中新增的一個(gè)方法,相對(duì)而言較為陌生。其作用是把的計(jì)算結(jié)果關(guān)聯(lián)到上即返回值作為新。實(shí)際上,乃縮寫(xiě),即二元函數(shù)之意類似。 本文以jdk1.8中HashMap.compute()方法為切入點(diǎn),分析其中難理解、有價(jià)值的源碼片段(類似源碼查看是ctrl+鼠標(biāo)左鍵的過(guò)程)。本篇涉及少許Java8(以下簡(jiǎn)稱J8)新特性,請(qǐng)?bào)H友們...
摘要:觀光線路圖將涉及到的源碼全局變量哈希表初始化長(zhǎng)度默認(rèn)值是負(fù)載因子默認(rèn)表示的填滿程度。根據(jù)是否為零將原鏈表拆分成個(gè)鏈表,一部分仍保留在原鏈表中不需要移動(dòng),一部分移動(dòng)到原索引的新鏈表中。 前言 本文以jdk1.8中HashMap.putAll()方法為切入點(diǎn),分析其中難理解、有價(jià)值的源碼片段(類似ctrl+鼠標(biāo)左鍵查看的源碼過(guò)程)。?觀光線路圖:putAll() --> putMapEnt...
閱讀 2183·2021-10-08 10:15
閱讀 1213·2019-08-30 15:52
閱讀 540·2019-08-30 12:54
閱讀 1562·2019-08-29 15:10
閱讀 2713·2019-08-29 12:44
閱讀 3035·2019-08-29 12:28
閱讀 3386·2019-08-27 10:57
閱讀 2241·2019-08-26 12:24