HashMap 和 LinkedHashMap的原理详解之HashMap

首先讲解HashMap的几个要点:

  • HashMap是非线程安全的(效率最高);HashTable是线程安全的效率最低;CurrentHashMap是线程安全的,CurrentHashMap 把内部分成若干个segment,每个segment内部是线程安全的(相当于HashTable),各个segment可以并行操作,因此它的性能优于HashTable 但是 弱于 HashMap。
  • 影响HashMap性能的3个关键参数,Capacity 、 loadFacor 和 threshold。Capacity为HashMap的size,loadFacor 为承载因子,threshold为承载界值。当map插入数据个数超过threshold的时候,则需要对HashMap进行动态扩容,扩容之后会对之前的插入的数据的位置进行重新计算和移动,因此每次扩容消耗都非常大,指定合理的 caption 和 loadFacor 对于HashMap的性能提升至关重要。
源码分析:
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY) {
            initialCapacity = MAXIMUM_CAPACITY;
        } else if (initialCapacity < DEFAULT_INITIAL_CAPACITY) {
            initialCapacity = DEFAULT_INITIAL_CAPACITY;
        }

        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        // Android-Note: We always use the default load factor of 0.75f.

        // This might appear wrong but it's just awkward design. We always call
        // inflateTable() when table == EMPTY_TABLE. That method will take "threshold"
        // to mean "capacity" and then replace it with the real threshold (i.e, multiplied with
        // the load factor).
        threshold = initialCapacity;
        init();
    }



    private void inflateTable(int toSize) {
        // Find a power of 2 >= toSize
        int capacity = roundUpToPowerOf2(toSize);

        // Android-changed: Replace usage of Math.min() here because this method is
        // called from the <clinit> of runtime, at which point the native libraries
        // needed by Float.* might not be loaded.
        **//capacity * loadFactor决定了临界值,如果hashmap的数量达到了临界值,则需要扩容一倍,**
        **//并且之前插入进来的数据需要重新计算位置,然后移动**
        float thresholdFloat = capacity * loadFactor;
        if (thresholdFloat > MAXIMUM_CAPACITY + 1) {
            thresholdFloat = MAXIMUM_CAPACITY + 1;
        }

        threshold = (int) thresholdFloat;
        table = new HashMapEntry[capacity];
    }
  • HashMap就是一个散列表,其内部结构如下:
    这里写图片描述

对于hashmap的内部结构分析如下:

  1. HashMap内部结构是通过array和list 共同构成。
  2. hashmap插入数据过程是 通过 hashcode来得到hash值,然后对hash值进行处理得到一个插入位置buckedindex,后续过程会分三种情况:
    a、如果通过哈希值计算出来的位置buckedIndex没有元素,则直接插入。
    b、如果buckedIndex存在即是hashcode存在,则比较 插入值的key 和 存在的key是否相等,即是equals方法的使用,如果相等,则用新值替换掉旧值。
    c、如果buckedIndex存在即是hashcode存在,则比较 插入值的key 和 存在的key是否相等,如果不相等,则将本数据插入到已存在数据链表的最前面,并且next指针指向后一个数据。
    根据b、c 2种情况的介绍,可以知道,如果hashcode相等,就是所谓hash散列碰撞了,碰撞之后则要采用equals方法 依次 比较碰撞位置的各个数据,如果存在key相等则直接更新该此值,如果不存在,则需要插入到本链表的最前面,并且next指针执行之前链表的第一个值。因为发生碰撞会进行各种equals,这里也是影响性能的一个方面,因此尽量减少碰撞的几率,会提高HashMap的性能。

以上是HashMap实现原理,下一个博文会详解LinkedHashMap,LinkedHashMap为什么能保存插入的顺序和实现LRU(最近最少访问),在LinkedHashMap详解中会进行详细描述,并且会解析LruCache实现原理。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值