hashMap 1.7

JDK1.7-
 数组+链表
 1.HashMap.put 返回值是原本的value, 如果当前的key是第一次插入,则返回的是null
 2.HashMap 插入在链表的时候,是头插入法。Node.next=arr[index]  arr[index]=Node;
 2.1 头插入会对每次扩容的时候,起作用。扩容的数组的链表和旧数组的链表的顺序是相反的。
   
 3.注意: 
   在 put操作的时候,如果先要判断key是否存在,这里要进行遍历,
   如果key存在,就把当前的key对应的value用当前key对应的value覆盖了。
   如果key不存在,还是插在链表的尾部,因为只有把链表全部遍历完,才能知道key是否存在。
  
   
 
 4.如何找出一个整数离它最近的比它大的2的幂次次数

   number=10;
   
     (number-1)<<1
     
   9  0000 1001
   18 0001 0010
    
    Integer.highestOneBit((number-1)<<1);

public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);
        i |= (i >>  2);
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);
        return i - (i >>> 1);
    }    
 
    1+2+4+8+16=31  int数据类型 最多31位 因为最高位保存符号位
    
      
      18      0001 0010   18
         
      >>1     0000 1001   9
    
       |      0001 1011   27
       
      >>2     0000 0110      6
      
       |      0001 1111   31
       
      >>4     0000 0001   1
      
       |      0001 1111   31
       
      >>8     0000 0000    0
      
       |      0001 1111    31
       
      >>16    0000 0000     0
      
       |      0000 1111     31
       
      
      return i - (i >>> 1);  
 
      0000 1111     31
      0000 0111     15
    - 0000 1000     16
      
      
      
    5.得到数组的下标(以前使用 index=num%数组的长度 效率低下)
       
       保证两个条件:
        *index的范围应为[0,len-1]
        *均匀分布在[0,len-1] 的范围上
        
        
       首先计算要 重新的 哈希数
        
          final int hash(Object k){
              int h=hashSeed;// hashSeed 默认为0
              if(h!=0&& k instanceof String){
                  return sun.misc.Hashing.StringHash32((Strng) k);
              }
              h^=k.hashCode(); // 0^任意数都是本身
              
              h^=(h>>>20)^(h>>>12);
              return h^(h>>>7)^(h>>>4);
          }
          
          
          上面为什么 要进行这么多的 右移运算 和异或运算?
              
             * 因为计算下标的时候, 它只和哈希后面的几位数有关,和其他前面的 哈希数都没有关系了,这样导致 哈希冲突比较重
                
               所以我们要 让哈希函数的高位 参与到 运算中, 所以要右移
               
          

          
          
          再计算 下标
          
          static int indexFor(int h,int length){
              return h&(length-1);
          }
          
          
          h: 0101 0101   length:16   length-1:15
          
          15: 0000 1111
          &  0000 0101 (竟然和原本的 h 的最后四位 一样, 这就是位运算的魅力)
          
          
         *计算出来的结果的范围是 [0000,1111] 的  即就是 [0,15] 
         
         
                                       (第一个好处)
         **  我们前面保证 数组的长度必须是 2的幂次方, 就是因为   h&数组的长度-1 刚刚好可以保证 index的范围应为[0,len-1]
          *  而 h 就是 利用 哈希函数计算出来的, 具有哈希函数的性质。
          
    
    
    6. key 为 null 
            
        *如果key==null 哈希函数就不会 在调用方法, 而是直接把 它封装成一个对象 放在 数组下标为0 的位置
           
        
    7. 扩容
         
        0.75(加载因子)
    
        threshold(阈值)=table.length*0.75;
          threshold=16*0.75=12;        
        
      *只有当前整个HashMap里面的数(size)>= threshold(阈值) 它才会扩容。
      * 其实还有一个条件(一般没注意) table[bucketIndex]!=null  (JDK7才会有这个条件)
        就是说当前这个值 所定位的数组里面有元素才会,扩容。
          
      
      扩展机制: 新的数组的长度是旧的数组的2倍
       
      
       如何把旧数组复制到新数组?
       *需要一个 双重循环, 访问到每一个元素,把每一个元素的hash重新计算出来
       *因为 它计算到下标 利用了数组的长度的,因此我们要重新计算每一个元素的下标
        
        细节:
             其实它计算出来只有两种情况
             第一种:在原来的位置。
             第二种:在原来的位置+oldTable.length
         
        举例说明:
            
            oldTable.length=16;
            
           一个数的 二进制为:0101 0101
            
           15: 0000 1111
            &             
           数: 0101 0101
               0000 0101
               
            
            数组的长度增长为32后:
               
               31:0001 1111
                      .           
                &    .
              数:0101 0101
                     .
                     .
                  0001 0101
                     .
                     .
             
             其实只和数的 低五位有关系,
             如果 它的低五位是0,则和原来的下标一样。
             如果 它的低五位是1, 则为 原来的小标+ oldTable.lenght
             
        扩容的目的:是为了让链表变短。
        

           
    8.线程
        *会出现循环链表

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值