HashMap的底层实现及Jdk 1.7-1.8的变化

  • 异、或、与–位运算二进制运算
    • &两位同时为“1”,结果才为“1”,否则为0
      • 1+1=1
    • |参加运算的两个对象只要有一个为1,其值为1。
      • 1+a=1
    • ^参加运算的两个对象,如果两个相应位为“异”(值不同),则该位结果为1,否则为0。
      • a+(!a)=1
      • a+a=0
  • hashmap
  1. hashmap的数据储存结构
    • Jdk 1.7由数组和链表结构组成
    • Jdk 1.8之后由数组,链表和红黑树组成,当链表长度大于8时就会转成红黑树结构
  2. HashMap的默认容量
    • 16
  3. HashMap的数组大小为什么初始空间是2的幂
    • 因为只有长度是2的n次方的数,进行减一操作得到的数的二进制结果的低位才能拿到全部是1的值,再进行按位与运算就能非常快速的拿到数组的下标,并且分布是均匀的
      static final int tableSizeFor(int cap) {
           int n = cap - 1;
           n |= n >>> 1;
           n |= n >>> 2;
           n |= n >>> 4;
           n |= n >>> 8;
           n |= n >>> 16;
           return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
       }
       例:14
       0000 1110
       n |= n >>> 1;      0000 1110  | 0000 0111    =  0000 1111
       n |= n >>> 2;      0000 1111  | 0000 0011    =  0000 1111
       ...
       n |= n >>> 16;     0000 1111  | 0000 0000    =  0000 1111
      
    • 在进行长度计算时,右移并或运算将低位全部补1,最后一步再+1就能得到2的幂
  4. HashMap扩容—resize
    • 当capacity(容量) * load(负载因子–0.75f) > threshold(预值)时进行扩容一倍
    • 1.7头插法
      • 将原来的数据迁移到新的hashmap中,并且要rehash
      • 数据迁移时哈希桶的链表的数据顺序进行调换
        • 当多线程同时进行数据的更改时,会产生循环链表,导致死锁
    • 1.8尾插法
      • 通过e.hash & oldCap来判断迁移后元素的新下标,并且新的链表的顺序和之前的顺序一致,从而避免了环形链表的出现

版权声明:本文为renxiaoxu_renxu原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。