[JDK8环境下的HashMap类应用及源码分析] 空构造函数初始化

作者主页:青花锁 简介:Java领域优质创作者、Java微服务架构公号作者、CSDN博客专家、京东推荐产品专利一作者
简历模板、学习资料、面试题库、技术互助

文末获取联系方式

系列文章目录

[Java基础] StringBuffer 和 StringBuilder 类应用及源码分析
[Java基础] 数组应用及源码分析
[Java基础] String,分析内存地址,源码
[JDK8环境下的HashMap类应用及源码分析] 第一篇 空构造函数初始化


文章目录

  • 系列文章目录
  • 前言
  • 1、使用无参的构造函数创建HashMap
    • 1.1、从空的构造函数入手分析
    • 1.2、查看map里元素的长度
    • 1.3、查看map所占的空间大小
    • 1.4、使用反射查看map所占的空间大小
  • 关键字
  • 相关项目实现推荐:
  • [查看更多博主首页更多实战项目 >>>](https://blog.csdn.net/s445320)


前言

HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。
HashMap 实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度,最多允许一条记录的键为 null,不支持线程同步。
HashMap 是无序的,即不会记录插入的顺序。
HashMap 继承于AbstractMap,实现了 Map、Cloneable、java.io.Serializable 接口。
[JDK8环境下的HashMap类应用及源码分析] 空构造函数初始化_第1张图片

1、使用无参的构造函数创建HashMap

     HashMap map = new HashMap<>();
     System.out.println("map里元素的长度:" +  map.size() );
     System.out.println("map所占的空间大小:" +  map.capacity() );

我们在这里创建一个HashMap对象,并打印2个信息:map里元素的长度、map所占的空间大小。(其中有一段是错误,稍后会讲到)

1.1、从空的构造函数入手分析

上述代码调用了HashMap的无参构造函数。
从注释可以看到, 构造了一个空的HashMap,使用默认的桶容量16 和 负载因子0.75(达到容量的0.75阈值,就触发扩容)

/**
     * Constructs an empty HashMap with the default initial capacity
     * (16) and the default load factor (0.75).
     */
    public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

1.2、查看map里元素的长度

map.size()

    /**
     * The number of key-value mappings contained in this map.
     */
    transient int size;
   /**
     * Returns the number of key-value mappings in this map.
     *
     * @return the number of key-value mappings in this map
     */
    public int size() {
        return size;
    }

这里的size使用的是Java基本类型int,初始值是0;
我们通过无参的构造函数,没有给size重新赋值,此时的size=0;

1.3、查看map所占的空间大小

map.capacity() 也就是桶容量,此代码【map所占的空间大小】在Idea里是报错的,编译不通过,但我们可以跟踪到JDK8的源代码,去自己计算此时桶容量大小是多少 :
capacity 方法不可重写,访问权限也是只能本类调用。

   /**
     * The next size value at which to resize (capacity * load factor).
     *
     * @serial
     */
    // (The javadoc description is true upon serialization.
    // Additionally, if the table array has not been allocated, this
    // field holds the initial array capacity, or zero signifying
    // DEFAULT_INITIAL_CAPACITY.)
    int threshold;
    
    transient Node<K,V>[] table;

    /**
     * The default initial capacity - MUST be a power of two.
     */
    static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
    
    final int capacity() {
        return (table != null) ? table.length :
            (threshold > 0) ? threshold :
            DEFAULT_INITIAL_CAPACITY;
    }

上述的代码里,有2个三元运算:
第一个:如果table 不等于null,就取table的长度,否则就取第二个三元运算的结果;
第二个:如果threshold 大于0,就取threshold 的数据,否则取默认容量值。

1、threshold的注释

  • DEFAULT_INITIAL_CAPACITY
    默认初始容量
  • Additionally, if the table array has not been allocated, this
    field holds the initial array capacity, or zero signifying
    此外,如果表数组尚未分配,则字段保持初始数组容量,或零表示 ,
  • The next size value at which to resize (capacity * load factor)
    要调整大小的下一个大小值(容量*负载系数)

也就是下一次扩容的阙值,元素个数达到这个阙值,整个容器就会扩容。

2、table
这里的table使用的是以K,V存储的Node节点集合,初始未赋值;
我们通过无参的构造函数,没有给table重新赋值,此时的table为null;

3、DEFAULT_INITIAL_CAPACITY
值=1 << 4; 采用二进制位运算,值为16
我们采用的是无参构造函数,因此经过2次三元计算比较,最终结果是DEFAULT_INITIAL_CAPACITY 。

1.4、使用反射查看map所占的空间大小

第1.3小节里,我们无法调用到HashMap的capacity方法,这里我们使用Java的反射技术来实现,调用capacity方法。

public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, InvocationTargetException, IllegalAccessException {

        HashMap map = new HashMap<>();

        //获取HashMap整个类
        Class<?> hashMapClszz = map.getClass();
        //获取指定属性,也可以调用getDeclaredFields()方法获取属性数组
        Field threshold =  hashMapClszz.getDeclaredField("threshold");
        //将目标属性设置为可以访问
        threshold.setAccessible(true);
        //获取指定方法,因为HashMap没有容量这个属性,但是capacity方法会返回容量值
        Method capacity = hashMapClszz.getDeclaredMethod("capacity");
        //设置目标方法为可访问
        capacity.setAccessible(true);

        //打印刚初始化的HashMap的元素数量、阈值、容量
        System.out.println("map里的元素数量:" +  map.size() );
//        System.out.println("map所占的空间大小:" +  map.capacity() );
        System.out.println("map触发扩容的阈值:" +  threshold.get(map) );
        System.out.println("map的容量:" +  capacity.invoke(map) );
}

查看效果:

map里的元素数量:0
map触发扩容的阈值:0
map的容量:16

关键字

  1. capacity:HashMap的容量,即哈希表中桶的数量。在创建HashMap时,可以指定初始容量,如果不指定,默认为16。当哈希表中的元素数量达到容量的75%时,会触发扩容操作。

  2. threshold:HashMap的阈值,即哈希表中元素数量的上限。当哈希表中元素数量达到阈值时,会触发扩容操作。阈值的计算公式为:threshold = capacity * loadFactor。其中,loadFactor是负载因子,它的默认值为0.75。

  3. size:HashMap中元素的数量。当向HashMap中添加元素时,size会自动增加;当从HashMap中删除元素时,size会自动减少。

  4. modCount:HashMap的修改次数。当向HashMap中添加或删除元素时,modCount会自动增加。在迭代HashMap时,如果发现modCount发生变化,则会抛出ConcurrentModificationException异常,防止在迭代过程中修改HashMap导致数据不一致的问题。

相关项目实现推荐:

查看更多博主首页更多实战项目 >>>

大家点赞、收藏、关注、评论啦 、查看微信公众号获取联系

WX:biancheng2019

精彩专栏推荐:

构建SpringCloud alibaba项目

Vue3实战

构建SpringBoot 项目

JavaScript小游戏

Java基础

博物馆管理系统实战

你可能感兴趣的:(Java基础,面试,HashMap,capacity,java)