<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-204  評(píng)論-149  文章-0  trackbacks-0

    Hashtable的結(jié)構(gòu),采用的是數(shù)據(jù)結(jié)構(gòu)中所說的鏈地址法處理沖突的方法

    從上面的結(jié)構(gòu)圖可以看出,Hashtable的實(shí)質(zhì)就是一個(gè)數(shù)組+鏈表。圖中的Entry就是鏈表的實(shí)現(xiàn),Entry的結(jié)構(gòu)中包含了對(duì)自己的另一個(gè)實(shí)例的引用next,用以指向另外一個(gè)Entry。而圖中標(biāo)有數(shù)字的部分是一個(gè)Entry數(shù)組,數(shù)字就是這個(gè)Entry數(shù)組的index。那么往Hashtable增加鍵值對(duì)的時(shí)候,index會(huì)根據(jù)鍵的hashcode、Entry數(shù)組的長度共同決定,從而決定鍵值對(duì)存放在Entry數(shù)組的哪個(gè)位置。從這種意義來說,當(dāng)鍵一定,Entry數(shù)組的長度一定的情況下,所得到的index肯定是相同的,也就是說插入順序應(yīng)該不會(huì)影響輸出的順序才對(duì)。然而,還有一個(gè)重要的因素沒有考慮,就是計(jì)算index出現(xiàn)相同值的情況。譬如代碼中 "sichuan" 和 "anhui",所得到的index是相同的,在這個(gè)時(shí)候,Entry的鏈表功能就發(fā)揮作用了:put方法通過Entry的next屬性獲得對(duì)另外一個(gè)Entry的引用,然后將后來者放入其中。根據(jù)debug得出的結(jié)果,"sichuan", "anhui"的index同為2,"hunan"的index為6,"beijing"的index為1,在輸出的時(shí)候,會(huì)以index遞減的方式獲得鍵值對(duì)。很明顯,會(huì)改變的輸出順序只有"sichuan"和"anhui"了,也就是說輸出只有兩種可能:"hunan" - "sichuan" - "anhui" - "beijing"和"hunan" - "anhui" - "sichuan" - "beijing"。以下是運(yùn)行了示例代碼之后,Hashtable的結(jié)果:


    在Hashtable的實(shí)現(xiàn)代碼中,有一個(gè)名為rehash的方法用于擴(kuò)充Hashtable的容量。很明顯,當(dāng)rehash方法被調(diào)用以后,每一個(gè)鍵值對(duì)相應(yīng)的index也會(huì)改變,也就等于將鍵值對(duì)重新排序了。這也是往不同容量的Hashtable放入相同的鍵值對(duì)會(huì)輸出不同的鍵值對(duì)序列的原因。在Java中,觸發(fā)rehash方法的條件很簡單:hahtable中的鍵值對(duì)超過某一閥值。默認(rèn)情況下,該閥值等于hashtable中Entry數(shù)組的長度×0.75。

     

    自 Java 2 平臺(tái) v1.2 以來,此類已經(jīng)改進(jìn)為可以實(shí)現(xiàn) Map,因此它變成了 Java Collections Framework 的一部分。與新集合的實(shí)現(xiàn)不同,Hashtable 是同步的。

    由迭代器返回的 Iterator 和由所有 Hashtable 的“collection 視圖方法”返回的 Collection 的 listIterator 方法都是快速失敗 的:在創(chuàng)建 Iterator 之后,如果從結(jié)構(gòu)上對(duì) Hashtable 進(jìn)行修改,除非通過 Iterator 自身的移除或添加方法,否則在任何時(shí)間以任何方式對(duì)其進(jìn)行修改,Iterator 都將拋出 ConcurrentModificationException因此,面對(duì)并發(fā)的修改,Iterator 很快就會(huì)完全失敗,而不冒在將來某個(gè)不確定的時(shí)間發(fā)生任意不確定行為的風(fēng)險(xiǎn)。由 Hashtable 的鍵和值方法返回的 Enumeration 不 是快速失敗的。

    注意,迭代器的快速失敗行為無法得到保證,因?yàn)橐话銇碚f,不可能對(duì)是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證。快速失敗迭代器會(huì)盡最大努力拋出 ConcurrentModificationException。因此,為提高這類迭代器的正確性而編寫一個(gè)依賴于此異常的程序是錯(cuò)誤做法:迭代器的快速失敗行為應(yīng)該僅用于檢測程序錯(cuò)誤。

    TestHashTable
    Hashtable中定義幾個(gè)內(nèi)部類(包括靜態(tài)的嵌套類和普通的內(nèi)部類)

    Hashtable中的Entry數(shù)據(jù)結(jié)構(gòu)
    Entry

    put方法:key的hash值不同但是可能放入的index相同,并且在放入之前需要判斷
    put方法

     1    public synchronized Enumeration<K> keys() {
     2    return this.<K>getEnumeration(KEYS);
     3    }

     4
     5    private <T> Enumeration<T> getEnumeration(int type) {
     6    if (count == 0{
     7        return (Enumeration<T>)emptyEnumerator;
     8    }
     else {
     9        return new Enumerator<T>(type, false);
    10    }

    11    }

    12
    13    public synchronized Enumeration<V> elements() {
    14    return this.<V>getEnumeration(VALUES);
    15    }

    16
    17Enumerator是Hashtable定義的一個(gè)內(nèi)部類
    18    private class Enumerator<T> implements Enumeration<T>, Iterator<T> {
    19    Entry[] table = Hashtable.this.table;//訪問宿主類的成員變量
    20    int index = table.length;
    21    Entry<K,V> entry = null;
    22    Entry<K,V> lastReturned = null;
    23    int type;
    24
    25    /**
    26     * Indicates whether this Enumerator is serving as an Iterator
    27     * or an Enumeration.  (true -> Iterator).
    28     */

    29    boolean iterator;
    30
    31    /**
    32     * The modCount value that the iterator believes that the backing
    33     * Hashtable should have.  If this expectation is violated, the iterator
    34     * has detected concurrent modification.
    35     */

    36    protected int expectedModCount = modCount;
    37}

    38內(nèi)部類中提供了訪問了hashtable中的entry數(shù)組的方法.
    39在實(shí)現(xiàn)Iterator接口中的方法時(shí)使用了expectedModCount變量來判斷是否有并發(fā)修改而導(dǎo)致fast-fail,而在Enumeration的接口方法實(shí)現(xiàn)中沒有判斷
    40
    41
    42
    43    public Set<K> keySet() {
    44    if (keySet == null)
    45        keySet = Collections.synchronizedSet(new KeySet(), this);
    46    return keySet;
    47    }

    48    private class KeySet extends AbstractSet<K> {
    49        public Iterator<K> iterator() {
    50        return
     getIterator(KEYS);
    51        }

    52        public int size() {
    53            return count;
    54        }

    55        public boolean contains(Object o) {
    56            return containsKey(o);
    57        }

    58        public boolean remove(Object o) {
    59            return Hashtable.this.remove(o) != null;
    60        }

    61        public void clear() {
    62            Hashtable.this.clear();
    63        }

    64    }

    65內(nèi)部類KeySet中有iterator接口方法的實(shí)現(xiàn),調(diào)用的宿主類的getIterator(KEYS)
    66    private <T> Iterator<T> getIterator(int type) {
    67    if (count == 0{
    68        return (Iterator<T>) emptyIterator;
    69    }
     else {
    70        return new Enumerator<T>(type, true);
    71    }

    72    }

    73getIterator中new 了一個(gè)新的內(nèi)部類Enumerator的對(duì)象,最終使用Enumerator來訪問hashtable的entry數(shù)組,能不能在內(nèi)部類中直接創(chuàng)建一個(gè)內(nèi)部類的的實(shí)例???
    74
    75
    76
    77    public Collection<V> values() {
    78    if (values==null)
    79        values = Collections.synchronizedCollection(new ValueCollection(),
    80                                                        this);
    81        return values;
    82    }

    83ValueCollection也是一個(gè)內(nèi)部類,結(jié)構(gòu)和KeySet功能差不多
    84    public Set<Map.Entry<K,V>> entrySet() {
    85    if (entrySet==null)
    86        entrySet = Collections.synchronizedSet(new EntrySet(), this);
    87    return entrySet;
    88    }

    89EntrySet也是內(nèi)部類,結(jié)構(gòu)和KeySet功能差不多

    posted on 2009-07-03 13:24 Frank_Fang 閱讀(8865) 評(píng)論(1)  編輯  收藏 所屬分類: Java編程

    評(píng)論:
    # re: Java Hashtable分析 2009-07-15 00:11 | Frank_Fang
    public class HashMap<K,V> 
    extends AbstractMap<K,V>
    implements Map<K,V>, Cloneable, Serializable
    
    

    基于哈希表的 Map 接口的實(shí)現(xiàn)。此實(shí)現(xiàn)提供所有可選的映射操作,并允許使用 null 值和 null 鍵。(除了不同步和允許使用 null 之外,HashMap 類與 Hashtable 大致相同。)此類不保證映射的順序,特別是它不保證該順序恒久不變。

    此實(shí)現(xiàn)假定哈希函數(shù)將元素正確分布在各桶之間,可為基本操作(getput)提供穩(wěn)定的性能。迭代集合視圖所需的時(shí)間與 HashMap 實(shí)例的“容量”(桶的數(shù)量)及其大?。ㄦI-值映射關(guān)系數(shù))的和成比例。所以,如果迭代性能很重要,則不要將初始容量設(shè)置得太高(或?qū)⒓虞d因子設(shè)置得太低)。

    HashMap 的實(shí)例有兩個(gè)參數(shù)影響其性能:初始容量加載因子容量 是哈希表中桶的數(shù)量,初始容量只是哈希表在創(chuàng)建時(shí)的容量。加載因子 是哈希表在其容量自動(dòng)增加之前可以達(dá)到多滿的一種尺度。當(dāng)哈希表中的條目數(shù)超出了加載因子與當(dāng)前容量的乘積時(shí),通過調(diào)用 rehash 方法將容量翻倍。

    通常,默認(rèn)加載因子 (.75) 在時(shí)間和空間成本上尋求一種折衷。加載因子過高雖然減少了空間開銷,但同時(shí)也增加了查詢成本(在大多數(shù) HashMap 類的操作中,包括 getput 操作,都反映了這一點(diǎn))。在設(shè)置初始容量時(shí)應(yīng)該考慮到映射中所需的條目數(shù)及其加載因子,以便最大限度地降低 rehash 操作次數(shù)。如果初始容量大于最大條目數(shù)除以加載因子,則不會(huì)發(fā)生 rehash 操作。

    如果很多映射關(guān)系要存儲(chǔ)在 HashMap 實(shí)例中,則相對(duì)于按需執(zhí)行自動(dòng)的 rehash 操作以增大表的容量來說,使用足夠大的初始容量創(chuàng)建它將使得映射關(guān)系能更有效地存儲(chǔ)。

    注意,此實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問此映射,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了該映射,則它必須 保持外部同步。(結(jié)構(gòu)上的修改是指添加或刪除一個(gè)或多個(gè)映射關(guān)系的操作;僅改變與實(shí)例已經(jīng)包含的鍵關(guān)聯(lián)的值不是結(jié)構(gòu)上的修改。)這一般通過對(duì)自然封裝該映射的對(duì)象進(jìn)行同步操作來完成。如果不存在這樣的對(duì)象,則應(yīng)該使用 Collections.synchronizedMap 方法來“包裝”該映射。最好在創(chuàng)建時(shí)完成這一操作,以防止對(duì)映射進(jìn)行意外的不同步訪問,如下所示:

     Map m = Collections.synchronizedMap(new HashMap(...));
    

    由所有此類的“集合視圖方法”所返回的迭代器都是快速失敗 的:在迭代器創(chuàng)建之后,如果從結(jié)構(gòu)上對(duì)映射進(jìn)行修改,除非通過迭代器自身的 removeadd 方法,其他任何時(shí)間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對(duì)并發(fā)的修改,迭代器很快就會(huì)完全失敗,而不冒在將來不確定的時(shí)間任意發(fā)生不確定行為的風(fēng)險(xiǎn)。

    注意,迭代器的快速失敗行為不能得到保證,一般來說,存在不同步的并發(fā)修改時(shí),不可能作出任何堅(jiān)決的保證??焖偈〉鞅M最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常程序的方式是錯(cuò)誤的,正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測程序錯(cuò)誤。



    public class LinkedHashMap<K,V> 
    extends HashMap<K,V>
    implements Map<K,V>

    Map 接口的哈希表和鏈接列表實(shí)現(xiàn),具有可預(yù)知的迭代順序。此實(shí)現(xiàn)與 HashMap 的不同之處在于,后者維護(hù)著一個(gè)運(yùn)行于所有條目的雙重鏈接列表。此鏈接列表定義了迭代順序,該迭代順序通常就是將鍵插入到映射中的順序(插入順序)。注意,如果在映射中重新插入 鍵,則插入順序不受影響。(如果在調(diào)用 m.put(k, v)m.containsKey(k) 返回了 true,則調(diào)用時(shí)會(huì)將鍵 k 重新插入到映射 m 中。)

    此實(shí)現(xiàn)可以讓客戶避免未指定的、由 HashMap(及 Hashtable)所提供的通常為雜亂無章的排序工作,同時(shí)無需增加與 TreeMap 相關(guān)的成本。使用它可以生成一個(gè)與原來順序相同的映射副本,而與原映射的實(shí)現(xiàn)無關(guān):

         void foo(Map m) {
    Map copy = new LinkedHashMap(m);
    ...
    }
    
    如果模塊通過輸入得到一個(gè)映射,復(fù)制這個(gè)映射,然后返回由此副本確定其順序的結(jié)果,這種情況下這項(xiàng)技術(shù)特別有用。(客戶通常期望返回的內(nèi)容與其出現(xiàn)的順序相同。)

    提供特殊的構(gòu)造方法來創(chuàng)建鏈接哈希映射,該哈希映射的迭代順序就是最后訪問其條目的順序,從近期訪問最少到近期訪問最多的順序(訪問順序)。這種映射很適合構(gòu)建 LRU 緩存。調(diào)用 putget 方法將會(huì)訪問相應(yīng)的條目(假定調(diào)用完成后它還存在)。putAll 方法以指定映射的條目集合迭代器提供的鍵-值映射關(guān)系的順序,為指定映射的每個(gè)映射關(guān)系生成一個(gè)條目訪問。任何其他方法均不生成條目訪問。特別是,collection 視圖上的操作 影響底層映射的迭代順序。

    可以重寫 removeEldestEntry(Map.Entry) 方法來實(shí)施策略,以便在將新映射關(guān)系添加到映射時(shí)自動(dòng)移除舊的映射關(guān)系。

    此類提供所有可選的 Map 操作,并且允許 null 元素。與 HashMap 一樣,它可以為基本操作(add、containsremove)提供穩(wěn)定的性能,假定哈希函數(shù)將元素正確分布到桶中。由于增加了維護(hù)鏈接列表的開支,其性能很可能比 HashMap 稍遜一籌,不過這一點(diǎn)例外:LinkedHashMap 的 collection 視圖迭代所需時(shí)間與映射的大小 成比例。HashMap 迭代時(shí)間很可能開支較大,因?yàn)樗枰臅r(shí)間與其容量 成比例。

    鏈接的哈希映射具有兩個(gè)影響其性能的參數(shù):初始容量加載因子。它們的定義與 HashMap 極其相似。要注意,為初始容量選擇非常高的值對(duì)此類的影響比對(duì) HashMap 要小,因?yàn)榇祟惖牡鷷r(shí)間不受容量的影響。

    注意,此實(shí)現(xiàn)不是同步的。如果多個(gè)線程同時(shí)訪問鏈接的哈希映射,而其中至少一個(gè)線程從結(jié)構(gòu)上修改了該映射,則它必須 保持外部同步。這一般通過對(duì)自然封裝該映射的對(duì)象進(jìn)行同步操作來完成。如果不存在這樣的對(duì)象,則應(yīng)該使用 Collections.synchronizedMap 方法來“包裝”該映射。最好在創(chuàng)建時(shí)完成這一操作,以防止意外的非同步訪問:

        Map m = Collections.synchronizedMap(new LinkedHashMap(...));
    
    結(jié)構(gòu)修改是指添加或刪除一個(gè)或多個(gè)映射關(guān)系,或者在按訪問順序鏈接的哈希映射中影響迭代順序的任何操作。在按插入順序鏈接的哈希映射中,僅更改與映射中已包含鍵關(guān)聯(lián)的值不是結(jié)構(gòu)修改。在按訪問順序鏈接的哈希映射中,僅利用 get 查詢映射不是結(jié)構(gòu)修改。

    Collection(由此類的所有 collection 視圖方法所返回)的 iterator 方法返回的迭代器都是快速失敗 的:在迭代器創(chuàng)建之后,如果從結(jié)構(gòu)上對(duì)映射進(jìn)行修改,除非通過迭代器自身的移除方法,其他任何時(shí)間任何方式的修改,迭代器都將拋出 ConcurrentModificationException。因此,面對(duì)并發(fā)的修改,迭代器很快就會(huì)完全失敗,而不冒將來不確定的時(shí)間任意發(fā)生不確定行為的風(fēng)險(xiǎn)。

    注意,迭代器的快速失敗行為無法得到保證,因?yàn)橐话銇碚f,不可能對(duì)是否出現(xiàn)不同步并發(fā)修改做出任何硬性保證??焖偈〉鲿?huì)盡最大努力拋出 ConcurrentModificationException。因此,編寫依賴于此異常的程序的方式是錯(cuò)誤的,正確做法是:迭代器的快速失敗行為應(yīng)該僅用于檢測程序錯(cuò)誤。

    此類是 Java Collections Framework 的成員。

      回復(fù)  更多評(píng)論
      
    主站蜘蛛池模板: 国产精品免费电影| 国产aa免费视频| 处破痛哭A√18成年片免费| 成人A级毛片免费观看AV网站| 成年女人色毛片免费看| 免费一级毛片免费播放| 亚洲中文字幕第一页在线 | 18禁免费无码无遮挡不卡网站 | 国产性生交xxxxx免费| 亚洲毛片不卡av在线播放一区| 国产日韩亚洲大尺度高清| 亚洲麻豆精品果冻传媒| 亚洲精品久久无码av片俺去也 | 亚洲五月综合缴情婷婷| 国产精品亚洲一区二区在线观看 | 亚洲GV天堂无码男同在线观看 | 在线观看亚洲AV每日更新无码| 免费人成在线观看播放a| 久久99免费视频| 无码人妻久久一区二区三区免费丨| 亚洲高清最新av网站| 亚洲成年轻人电影网站www| 亚洲国产成人无码AV在线影院| 中文字幕无线码免费人妻| 黄+色+性+人免费| 亚洲国产精品专区在线观看| 亚洲综合精品一二三区在线| 亚洲国产精品18久久久久久| 日韩精品免费视频| 在线观看国产情趣免费视频| 亚洲国产精品嫩草影院在线观看| 羞羞视频在线免费观看| 中文毛片无遮挡高清免费| 国产精品久久永久免费| 亚洲Av无码乱码在线播放| 久久久久亚洲AV无码专区体验| 精品成人一区二区三区免费视频 | 欧美男同gv免费网站观看| 亚洲综合色视频在线观看| 亚洲中文字幕久在线| 精选影视免费在线 |