zoukankan      html  css  js  c++  java
  • HashMap底层实现原理

    HashMap在底层数据结构

    采用了数组+链表+红黑树,(内部实现是一个桶数组,每个桶中存放着一个单链表的头结点,当链表长度大于8的时候转换为红黑树。)

    通过散列映射来存储键值对数据因为在查询上使用散列码(通过键生成一个数字作为数组下标,这个数字就是hash code)

    所以在查询上的访问速度比较快,HashMap最多允许一对键值对的Key为Null,允许多对键值对的value为Null。它是非线程安全的。在排序上面是无序的。

    HashMap的主要成员变量:

    transient Node<K,V>[] table:这是一个Node类型的数组(也有称作Hash桶),可以从下面源码中看到静态内部类Node在这边可以看做就是一个节点,多个Node节点构成链表,当链表长度大于8的时候转换为红黑树。

    transient int size:表示当前HashMap包含的键值对数量

    transient int modCount:表示当前HashMap修改次数

    int threshold:表示当前HashMap能够承受的最多的键值对数量,一旦超过这个数量HashMap就会进行扩容

    final float loadFactor:负载因子,用于扩容

    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4:默认的table初始容量

    static final float DEFAULT_LOAD_FACTOR = 0.75f:默认的负载因子


    扩容机制核心方法Node<K,V>[] resize():
     HashMap扩容可以分为三种情况:

    第一种:使用默认构造方法初始化HashMap。从前文可以知道HashMap在一开始初始化的时候会返回一个空的table,并且thershold为0。因此第一次扩容的容量为默认值DEFAULT_INITIAL_CAPACITY也就是16。同时threshold = DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR = 12。

    第二种:指定初始容量的构造方法初始化HashMap。那么从下面源码可以看到初始容量会等于threshold,接着threshold = 当前的容量(threshold) * DEFAULT_LOAD_FACTOR。

    第三种:HashMap不是第一次扩容。如果HashMap已经扩容过的话,那么每次table的容量以及threshold量为原有的两倍。
    这边也可以引申到一个问题就是HashMap是先插入数据再进行扩容的,但是如果是刚刚初始化容器的时候是先扩容再插入数据。

    负载因子为什么会影响HashMap性能

    我们都知道有序数组存储数据,对数据的索引效率都很高,但是插入和删除就会有性能瓶颈(回忆ArrayList),

    链表存储数据,要一次比较元素来检索出数据,所以索引效率低,但是插入和删除效率高(回忆LinkedList),

    两者取长补短就产生了哈希散列这种存储方式,也就是HashMap的存储逻辑.

    负载因子表示一个散列表的空间的使用程度,有这样一个公式:initailCapacity*loadFactor=HashMap的容量。

    所以负载因子越大则散列表的装填程度越高,也就是能容纳更多的元素,元素多了,链表大了,所以此时索引效率就会降低。

    反之,负载因子越小则链表中的数据量就越稀疏,此时会对空间造成浪费,但是此时索引效率高。

  • 相关阅读:
    栈的概念
    什么是 JavaConfig?
    数据库连接池的原理。为什么要使用连接池。
    根据你以往的经验简单叙述一下MYSQL的优化
    动态横切
    横切技术
    什么是AOP
    BIO ,NIO ,AIO 有什么区别?
    简述Comparable和Comparator两个接口的区别
    Spring Boot 客户端?
  • 原文地址:https://www.cnblogs.com/yuyangcoder/p/9851052.html
Copyright © 2011-2022 走看看