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

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

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

    posts - 28,  comments - 15,  trackbacks - 0
        HashMap內部有一個Entry數組,可以稱之為hash table。HashMap的默認構造值為初始容量為16,負載因子為0.75,閥值(初始容量*負載因子)為12。其默認構造子如下:
    public class HashMap<K,V>
        
    extends AbstractMap<K,V>
        
    implements Map<K,V>, Cloneable, Serializable
    {

        
    /**
         * The default initial capacity - MUST be a power of two.
         
    */

        
    static final int DEFAULT_INITIAL_CAPACITY = 16;

        
    /**
         * The maximum capacity, used if a higher value is implicitly specified
         * by either of the constructors with arguments.
         * MUST be a power of two <= 1<<30.
         * 
         * 如果一個較大的值被任意一個帶有參數的構造器指定,最大容量被使用。
         
    */

        
    static final int MAXIMUM_CAPACITY = 1 << 30;   //1073741824

        
    /**
         * The load factor used when none specified in constructor.
         
    */

        
    static final float DEFAULT_LOAD_FACTOR = 0.75f;

        
    /**
         * The table, resized as necessary. Length MUST Always be a power of two.
         
    */

        
    transient Entry[] table;

        
    /**
         * The number of key-value mappings contained in this map.
         
    */

        
    transient int size;

        
    /**
         * The next size value at which to resize (capacity * load factor).
         * 
         * 下一個用來調整的大小值
         * 
    @serial
         
    */

        
    int threshold;

        
    /**
         * The load factor for the hash table.
         *
         * 
    @serial
         
    */

        
    final float loadFactor;

    public HashMap() {
            
    this.loadFactor = DEFAULT_LOAD_FACTOR;  
            threshold 
    = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
            table 
    = new Entry[DEFAULT_INITIAL_CAPACITY];  //默認情況下,以容量為16構建Entry數組
            init();
        }


    put方法分析:
     <1>HashMap首先判斷key是否為null,如果為null,
        <1.1>HashMap從hash table中第0個位置的Entry,如果該Entry不等于null且entry.key也不為null,當前value覆蓋entry的value。
        <1.2>否則,在hash table[0]處創建新的key=null的Entry。
     <2>
        接下來,以key的hashcode做hash運算,獲得hash值。該hash值與hash table的長度-1做與操作,獲得key在當前hash table中的位置索引。
        然后檢查在該索引位置是否存在Entry對象,如果存在,且該Entry對象的key的hash值與上面計算的hash值相等,且entry的key與傳入的key相等或者key.equals(entry.key),那么以當前的value值覆蓋舊值,并返回舊值。
        如果hash table中不存在key所指定的Entry,那么就要增加新的Entry。在增加Entry后,要檢查容量是否已經達到閥值,如果達到閥值,就以當前hash table的長度的2倍擴展。同時要重新計算entry在新的hash table中的索引位置。注意,由于hash計算可能導致key的hash值可能是重復的,HashMap采用鏈表的方式解決hash值沖突的問題,另外一種解決方法是開放地址法。
        以下是put方法部分代碼:
    public V put(K key, V value) {
            
    if (key == null)
                
    return putForNullKey(value);
            
            
    /*這里對key的hasCode做hash*/
            
    int hash = hash(key.hashCode());
            
    /*通過hash值與hash表的長度減1做與操作獲取hash表的索引值*/
            
    int i = indexFor(hash, table.length);
            
    /*由于hash可能重復,導致獲取重復的索引值,這里通過判斷傳入的key的has值與當前節點的key的has值是否相等,且key相等或者equals相等,來用新的value替換舊值,并返回舊值*/
            
    for (Entry<K,V> 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;
        }


    處理key為空的情況:

     private V putForNullKey(V value) {
            
    /*從0桶查找key為null的Entry。如果桶中有null的Entry,那么把當前新的值設置到Entry中,并返回舊值*/
            
    for (Entry<K,V> e = table[0]; e != null; e = e.next) {
                
    if (e.key == null{
                    V oldValue 
    = e.value;
                    e.value 
    = value;
                    e.recordAccess(
    this);
                    
    return oldValue;
                }

            }

            
            modCount
    ++;
            addEntry(
    0null, value, 0);
            
    return null;
        }

    計算key的hash值與計算key所應處在hash table中的位置:

    static int hash(int h) {
            
    // This function ensures that hashCodes that differ only by
            
    // constant multiples at each bit position have a bounded
            
    // number of collisions (approximately 8 at default load factor).
            h ^= (h >>> 20^ (h >>> 12);
            
    return h ^ (h >>> 7^ (h >>> 4);
        }


        
    /**
         * Returns index for hash code h.
         
    */

        
    static int indexFor(int h, int length) {
            
    return h & (length-1);
        }

    增加entry節點以及擴容:

     void addEntry(int hash, K key, V value, int bucketIndex) {
            Entry
    <K,V> e = table[bucketIndex];//臨時存儲指定桶索引的Entry
            table[bucketIndex] = new Entry<K,V>(hash, key, value, e);//在指定桶索引位置創建新的Entry,并自動把原桶索引的Entry作為當前Entry的next
            /*當size達到閥值(當前容量*負載因子=threshold),需要擴容*/
            
    if (size++ >= threshold)
                resize(
    2 * table.length);
        }

    ------------------------------------------------

     void resize(int newCapacity) {
            Entry[] oldTable 
    = table;
            
    int oldCapacity = oldTable.length;
            
    /*如果就有容量達到默認的的容量最大值(2的30次方),threshold設為整形的最大值(2的31次方-1)*/
            
    if (oldCapacity == MAXIMUM_CAPACITY) {
                threshold 
    = Integer.MAX_VALUE;
                
    return;
            }


            Entry[] newTable 
    = new Entry[newCapacity];
            
    /*這里把源hash表中的數據拷貝到新的hash表中,注意的是,源hash表中鏈表到新hash表中由頭變成了尾*/
            transfer(newTable);
            table 
    = newTable;
            
    /*設置擴容后新的閥值*/
            threshold 
    = (int)(newCapacity * loadFactor);
        }


    get方法分析:
        當調用get方法時,HashMap首先判斷key是否為null,如果為null,其hash值為0,否則通過hash算法計算。
        接下來,通過該hash值與hash table的長度-1做與操作,獲得key在hash table中的索引。如果entry不等null,且該傳入key的hash值與entry的hash值相等,且key==entry.key或者key.equals(entry.key),則返回該entry.value.否則返回null.

        final Entry<K,V> getEntry(Object key) {
            
    int hash = (key == null? 0 : hash(key.hashCode());
            
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
                 e 
    != null;
                 e 
    = e.next) {
                Object k;
                
    if (e.hash == hash &&
                    ((k 
    = e.key) == key || (key != null && key.equals(k))))
                    
    return e;
            }

            
    return null;
        }







     


     

     

     

     

     

     

     

     

     

     

     

    posted on 2012-02-13 14:42 zhangxl 閱讀(420) 評論(0)  編輯  收藏 所屬分類: JDK

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    <2012年2月>
    2930311234
    567891011
    12131415161718
    19202122232425
    26272829123
    45678910

    常用鏈接

    留言簿(1)

    隨筆分類(17)

    隨筆檔案(28)

    文章分類(30)

    文章檔案(30)

    相冊

    收藏夾(2)

    hibernate

    java基礎

    mysql

    xml

    關注

    壓力測試

    算法

    最新隨筆

    搜索

    •  

    積分與排名

    • 積分 - 96260
    • 排名 - 601

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲狠狠色丁香婷婷综合| 亚洲综合色成在线播放| 亚洲精品美女久久久久99| 老牛精品亚洲成av人片| 精品国产免费观看一区| 亚洲男人天堂2022| 99视频在线精品免费观看6| 一本色道久久88亚洲精品综合| 中文字幕无码不卡免费视频| 亚洲日韩一中文字暮| 日韩a级毛片免费观看| 婷婷亚洲综合五月天小说在线| 亚洲精品美女久久777777| 麻豆国产精品入口免费观看| 永久免费A∨片在线观看| 久久久久亚洲AV无码网站| 成人免费在线看片| 亚洲色欲色欲www| 日本成人在线免费观看| 全黄大全大色全免费大片| 亚洲av最新在线网址| 亚洲大片免费观看| 亚洲国产一区在线| 无遮免费网站在线入口| 亚洲日本成本人观看| 亚洲av无码国产精品色午夜字幕| 韩国欧洲一级毛片免费| 亚洲国产精品免费在线观看| 精品97国产免费人成视频| 久久久久亚洲av无码专区喷水 | 吃奶摸下高潮60分钟免费视频 | 久久精品国产大片免费观看| 亚洲视频一区在线| 好男人看视频免费2019中文| 亚洲精品黄色视频在线观看免费资源 | 久久亚洲AV成人无码国产| 亚洲综合亚洲综合网成人| 国产精品免费视频播放器| a级片免费在线观看| 日韩亚洲综合精品国产| 亚洲日韩AV一区二区三区中文|