HashMap学习总结

本文主要介绍了HashMap、HashTable和ConcurrentHashMap类。HashMap由数组、链表和红黑树构成,线程不安全,存储和查找效率高;HashTable是线程安全类,但已过时,效率低;ConcurrentHashMap是常用的键值对并发容器,锁粒度小,性能较好。还介绍了它们的数据结构、重要参数等信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、HashMap类

  1. 数据结构:由数组、链表和红黑树(JDK1.8开始)构成;
  2. 存储和查找效率很高,但是是线程不安全的类,不适用于并发环境中。若想在高并发的情况下使用,可以使用Collections.syncronizedMap()来进行包装,或使用HashTable类、ConcurrentHashMap类;(在JDK1.7及以上版本,建议使用ConcurrentHashMap)
  3. 当链表长度大于8是,会生成红黑树,相对于只使用链表的结构,有更高的读写效率;
  4. 重要的参数值:
    • 初始容量是16;
    • 默认的加载因子(loadFactor)是0.75,加载因子的设置是在权衡时间和空间基础上进行设置的;该值可以大于1,在时间需求高的情况下可以,设置更小的填充因子;在空间需求高而时间需求不高的情况下,设置更大的填充因子;
    • 扩容因子是2,当capacity需要被扩容时,容量翻倍;
  5. HashMap的容量:一定是2的n次方,当输入的值不是2的n次方的时候,会通过tableSizeFor方法,获得比输入值大的2的n次方;
        /**
         * Returns a power of two size for the given target capacity.
         */
        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;
        }
    
  6. Hash算法:取key的hashCode值、高位运算、取模运算
    不管增加、删除、查找键值对,定位到哈希桶数组的位置都是很关键的第一步。
    我们的目的是希望HashMap里面的元素位置尽量分布均匀些,尽量使得每个位置上的元素数量只有一个,那么当我们用hash算法求得这个位置的时候,马上就可以知道对应位置的元素就是我们要的,不用遍历链表,大大优化了查询的效率。HashMap定位数组索引位置,直接决定了hash方法的离散性能
    //方法一:
    static final int hash(Object key) {   //jdk1.8 & jdk1.7
         int h;
         // h = key.hashCode() 为第一步 取hashCode值
         // h ^ (h >>> 16)  为第二步 高位参与运算
         return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }
    //方法二:
    static int indexFor(int h, int length) {  
    //jdk1.7的源码,jdk1.8没有这个方法,但是实现原理一样的
         return h & (length-1);  //第三步 取模运算
    }
    
    HashMap的容量是2的N次方,当length总是2的n次方时,h& (length-1)运算等价于对length取模,也就是h%length,但是&比%具有更高的效率。
    在JDK1.8的实现中,优化了高位运算的算法,通过hashCode()的高16位异或低16位实现的:(h = k.hashCode()) ^ (h >>> 16),主要是从速度、功效、质量来考虑的,这么做可以在数组table的length比较小的时候,也能保证考虑到高低Bit都参与到Hash的计算中,同时不会有太大的开销。

学习参考:https://tech.meituan.com/2016/06/24/java-hashmap.html

二、HashTable类

学习HashMap就不得不同时对比一下HashTable类(虽然该类已经过时了)

  1. HashTable类是一个线程安全的类,每个方法都实现了syncronized同步,因此多个线程对于该类的访问是串行化的。特别是HashTable中键值对超过了一定的数量时,执行效率会非常低。
  2. 数据结构:由数组和链表构成;
  3. 重要的参数值:
    • 初始容量是13;
    • 默认的加载因子(loadFactor)是0.75与HashMap一样;
    • 默认扩容是原来容量的两倍加1;
  4. 与HashMap不同的是HashTable不可以接受null值(HashMap可以接受一个key为空,多个值为空);

三、ConcurrentHashMap类

该类是JDK1.7之后最常用的键值对并发容器

  1. 数据结构:syncronized+CAS+HashEntry+红黑树;
  2. 性能:因为锁粒度远远小于HashTable类,只有当数组中发生hash碰撞时,才对HashEntry加同步锁。并不会影响其他HashEntry对象的数据的读写;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值