码迷,mamicode.com
首页 > 其他好文 > 详细

HashMap

时间:2015-07-04 00:51:34      阅读:169      评论:0      收藏:0      [点我收藏+]

标签:

【HashMap 】

基于哈希表的 Map 接口的实现。
此实现提供所有可选的映射操作,并允许使用 null 值和 null 键。
 
 
 

【HashMap为什么两倍扩容?】

为什么按照2倍这就是hashmap的精妙之处,里面有个查找索引的算法 hashcode & (size-1)这个算法可以让元素均匀的分布在不同的索引上。
 
arraylist 初始容量是10,所以不想让它在添加元素的时候发生resize事先就要预估好定义的容量,频繁resize很耗性能(先按照*3/2+1进行扩容,然后 在拷贝),针对它进行修改其实是一样的道理,查询就是迭代遍历然后比较。hashmap数组+链表,key唯一,查询快如果元素在散列表中分布均匀,那么 就是数组下标定位查询,如果分布不均匀,即根据key值计算出来的数组下标已经被其他元素占用,这个时候就要在这个元素上使用链表来存放这个新元素了。所 以上面的查询有可能还需要进行链表的遍历。插入也一样。扩容是按照实际大小>阈值*初始容量时进行2倍扩容。
 
强力建议我们在项目中如果知道范围的情况下,我们应该手动指定初始大小 像这样
Map<Integer,String> maps=new HashMap<Integer,String>(1000);
 

【put()】

后添加的在链表前面。
void addEntry(int hash,K key,V value,int bucketIndex)
table[bucketIndex] = new Entry(hash,key,value,table[bucketIndex]);
 
public V put(K key, V value)  
 {  
     // 如果 key 为 null,调用 putForNullKey 方法进行处理  
     if (key == null)  
         return putForNullKey(value);  
     // 根据 key 的 keyCode 计算 Hash 值  
         int hash = hash(key.hashCode());  
     // 搜索指定 hash 值在对应 table 中的索引  
         int i = indexFor(hash, table.length);  
     // 如果 i 索引处的 Entry 不为 null,通过循环不断遍历 e 元素的下一个元素  
     for (Entry<K,V> e = table[i]; e != null; e = e.next)  
     {  
         Object k;  
         // 找到指定 key 与需要放入的 key 相等(hash 值相同  
         // 通过 equals 比较放回 true)  
         if (e.hash == hash && ((k = e.key) == key  
             || key.equals(k)))  
         {  
             V oldValue = e.value;  
             e.value = value;  
             e.recordAccess(this);  
             return oldValue;  
         }  
     }  
     // 如果 i 索引处的 Entry 为 null,表明此处还没有 Entry  
     modCount++;  
     // 将 key、value 添加到 i 索引处  
     addEntry(hash, key, value, i);  
     return null;  
 }
 
 
static int hash(int i){
    h ^= (h>>>20)^(h>>>12);
    return h^(h>>>7)^(h>>>4);
}
 
 
【Hash存储机制】
static int hash(int h)  
{  
    h ^= (h >>> 20) ^ (h >>> 12);  
    return h ^ (h >>> 7) ^ (h >>> 4);  
}
 
static int indexFor(int h, int length)  
{  
    return h & (length-1);  
}
 
当 length 总是 2 的倍数时,h & (length-1)将是一个非常巧妙的设计:假设 h=5,length=16, 那么 h & length - 1 将得到 5;如果 h=6,length=16, 那么 h & length - 1 将得到 6 ……如果 h=15,length=16, 那么 h & length - 1 将得到 15;但是当 h=16 时 , length=16 时,那么 h & length - 1 将得到 0 了;当 h=17 时 , length=16 时,那么 h & length - 1 将得到 1 了……这样保证计算得到的索引值总是位于 table 数组的索引之内。
 


 

【Fail-Fast机制】

volatile的modCount域。
        java.util 包中的集合类都返回 fail-fast 迭代器,这意味着它们假设线程在集合内容中进行迭代时,集合不会更改它的内容。如果 fail-fast 迭代器检测到在迭代过程中进行了更改操作,那么它会抛出 ConcurrentModificationException ,这是不可控异常。
      在迭代过程中不更改集合的要求通常会对许多并发应用程序造成不便。相反,比较好的是它允许并发修改并确保迭代器只要进行合理操作,就可以提供集合的一致视图,如 java.util.concurrent 集合类中的迭代器所做的那样。
     java.util.concurrent 集合返回的迭代器称为弱一致的(weakly consistent) 迭代器。对于这些类,如果元素自从迭代开始已经删除,且尚未由 next() 方法返回,那么它将不返回到调用者。如果元素自迭代开始已经添加,那么它可能返回调用者,也可能不返回。在一次迭代中,无论如何更改底层集合,元素不会被返回两次。

HashMap

标签:

原文地址:http://www.cnblogs.com/lsx1993/p/4619969.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!