HashMap、HashTable和Vector的存储扩容解析

2023-11-11

HashMap、HashTable和Vector是面试时比较高频问到的知识点,今天就从三个的底层源码的角度分析三者之间的存储、扩容原理和异同点。

HashMap:实现Map接口

                      

实现原理:HashMap采用链地址法。即底层是一个数组实现。数组的每一项(即一个Entry)又是一个链表。结构图如下:

每个Entry是一个键值对。源码如下:

  1. 1. transient Entry[] table;
  2. 2.
  3. 3. static class Entry<K,V> implements Map.Entry<K,V> {
  4. 4. final K key;
  5. 5. V value;
  6. 6. Entry<K,V> next;
  7. 7. final int hash;
  8. 8. ……
  9. 9. }

HashMap的存储机制:首先根据key计算出该key对应的Entry在数组中的位置,然后判断是否该Entry是否在该位置对应的链表中,如果不在,则插入链表的头部,如果在,则更新该链表中对应Entry的value。

HashMap计算key所属数组的位置方法:首先计算key的hash值,然后根据hash函数hashcode & (length - 1)计算出所在数组的位置(因为HashMap的数组长度为2的整数幂,所以采用位运算的结果和hash % length相同,但是位运算的效率要远高于求余运算)。源码如下:

  1. 1. static int indexFor(int h, int length) {
  2. 2. return h & (length- 1);
  3. 3. }
HashMap的扩容:每当初始化一个HashMap,默认的数组大小(table.size)为16,默认的增长因子(loadFactor)为0.75,;当元素个数超过数组大小的loadFactor   时,就会 对数组进行扩容。HashMap采用的扩容方法为:每次把数组大小扩大一倍,然后重新计算HashMap中每个元素在数组中的位置。也可以   自定义扩展容量的大小( HashMap(int initialCapacity))。


HashTable:实现了Map接口,同时也是Dictionary抽象类的具体实现。

HashTable通过Synchronize实现线程安全。实现原理与HashMap相同,也是采用数组+链表的结构实现。不同于HashMap的是:

1) HashTable的默认大小为11

2) 数组位置的计算方法不同;HashTable的 index = (hashcode & Integer.MAX_VALUE) % table.length

3) 扩容的方法不一样;newlength = oldlength * 2 + 1

4) 在使用中,HashTable不允许key值为null,也不允许value为null


Vector:实现了List接口,是一个用Synchronize修饰的线程安全的动态数组。

扩容方法:

1,计算新容量大小。NewSize = oldSize + (Increment>0 ) ? Increment:oldSize。(如果增长因子小于零,每次扩容大小为增长前的一倍,如果增长因子大于零,则每次扩容大小为增长因子的大小)

 2,判断新容量大小和最小需求大小。如果小于最小需求,则把最小需求容量复制给新容量。

3,如果新容量大小大于数组最大容量,则判断最小需求大小和最大数组容量大小;如果最小需求大小大于最大数组容量,则最终新容量为Integer.MaxValue,反之则最终新容量大小为最大数组容量(最大数组容量 = Integer.MaxValue-8)。

设置第三步的原因:vector的增长不是无节制的。Vector的最大长度限制为Integer.MaxValue,所以在第二步计算出新容量大小后,需要比较新容量大小和最大数组容量大小,如果大于,则对最小需求容量调用最终容量计算函数来求出最终的容量。

源码分析:

  1. /**
  2. * This implements the unsynchronized semantics of ensureCapacity.
  3. * Synchronized methods in this class can internally call this
  4. * method for ensuring capacity without incurring the cost of an
  5. * extra synchronization.
  6. *
  7. * @see #ensureCapacity(int)
  8. */
  9. private void ensureCapacityHelper(int minCapacity) {
  10. // overflow-conscious code
  11. if (minCapacity - elementData.length > 0)
  12. grow(minCapacity);
  13. }
  14. /**
  15. * The maximum size of array to allocate.
  16. * Some VMs reserve some header words in an array.
  17. * Attempts to allocate larger arrays may result in
  18. * OutOfMemoryError: Requested array size exceeds VM limit
  19. */
  20. private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  21. private void grow(int minCapacity) {
  22. // overflow-conscious code
  23. int oldCapacity = elementData.length;
  24. //步骤一 设置新容量
  25. int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
  26. capacityIncrement : oldCapacity);
  27. //步骤二 比较新容量和需求容量
  28. if (newCapacity - minCapacity < 0)
  29. newCapacity = minCapacity;
  30. //步骤三 保证Vector不会不限制增长
  31. if (newCapacity - MAX_ARRAY_SIZE > 0)
  32. newCapacity = hugeCapacity(minCapacity);
  33. elementData = Arrays.copyOf(elementData, newCapacity);
  34. }
  35. private static int hugeCapacity(int minCapacity) {
  36. if (minCapacity < 0) // overflow
  37. throw new OutOfMemoryError();
  38. return (minCapacity > MAX_ARRAY_SIZE) ?
  39. Integer.MAX_VALUE :
  40. MAX_ARRAY_SIZE;
  41. }


版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YHYR_YCY/article/details/52535281



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

HashMap、HashTable和Vector的存储扩容解析 的相关文章

  • 天猫精灵-土味情话

    1 你猜我想喝什么 不知道啊 我想呵护你 2 你为什么要害我呀 害你什么了 害我喜欢你呀 3

随机推荐

  • qt把ui文件加入到类中

    有一个ui界面 需要建立 cpp和 h文件 ui的名字是Ui Form 代码如下 h文件 pragma once include ui add1 h class Form1 public QWidget Q OBJECT public Fo
  • 以法律的名义捍卫自由软件的权益之二 —— 软件自由法律中心(SFLC)的来龙去脉...

    更多精彩推荐 请关注开源之道 Thu Apr 24 2020 7347 Words 大约需要阅读 2 分钟 作者 开源之道 在介绍完成以法律的名义捍卫自由软件的权益之一 软件自由保护组织 SFC 的来龙去脉 笔者觉得有点不足的地方 尽管基本
  • 使用docker和docker-compose搭建Vulhub漏洞测试靶场

    使用docker和docker compose搭建Vulhub漏洞测试靶场 1 安装Docker和docker compose docker安装步骤 docker compose安装步骤 2 下载vulhub 安装完成docker和dock
  • Arduino的传感器使用教程1:PM2.5、温度和大气压传感器

    来自我的个人网站 http wangbch com ARDUINO SENSOR Arduino Temperature PM2 5 Atmos Arduino测定温度 PM2 5以及大气压 Temperature Measure and
  • 猜字母

    猜字母 把abcd s共19个字母组成的序列重复拼接106次 得到长度为2014的串 接下来删除第1个字母 即开头的字母a 以及第3个 第5个等所有奇数位置的字母 得到的新串再进行删除奇数位置字母的动作 如此下去 最后只剩下一个字母 请写出
  • mongoDB介绍与客户端认证权限

    mongoDB简介 Mongo 是 humongous 的中间部分 在英文里是 巨大无比 的意思 所以 MongoDB 可以翻译成 巨大无比的数据库 更优雅的叫法是 海量数据库 Mongodb是一款非关系型数据库 说到非关系型数据库 区别于
  • State Hook

    State Hook State Hook是一个在函数组件中使用的函数 useState 用于在函数组件中使用状态 useState 函数有一个参数 这个参数的值表示状态的默认值 函数的返回值是一个数组 该数组一定包含两项 第一项 当前状态
  • 华为OD机试 - 数据最节约的备份方法(Java )

    题目描述 有若干个文件 使用刻录光盘的方式进行备份 假设每张光盘的容量是500MB 求使用光盘最少的文件分布方式 所有文件的大小都是整数的MB 且不超过500MB 文件不能分割 分卷打包 输入描述 一组文件大小的数据 输出描述 使用光盘的数
  • github/gitlab中的fork操作

    在git中 fork是 分叉 复制 的意思 fork可以复制出一个仓库的新拷贝 包含了原有库中的所有提交记录 fork后这个代码库是完全独立的 可以在自己的库中做任何修改 也可以向原来的库提交合并请求 git中fork是什么意思 githu
  • transition将鼠标悬停在一个div元素上,逐步改变表格的宽度从100px到300px::

  • Lock 接口与 synchronized 关键字的区别

    拷贝别的博主总结的9点不同 1 JDK版本不同 synchronized关键字产生于JKD1 5之前 是低版本保证共享资源同步访问的主要技术 Lock接口产生于JDK1 5版本 位于著名的java util concurrent并发包中 是
  • 2018年WiFi、5G和蓝牙的发展以及与VR/AR的联系

    52VR大幅修正了原译文的翻译错误并作润饰编辑 这份文章中涵盖对无线技术们在2018年的表现之期待 包括可能实现的时间 以及它们将可能会怎样影响AR VR的版图 首先我们展望一下 不得不说的是2018年将是很多技术大转折的一年 这其中包括手
  • delphi listview动态添加图片_Qml组件化编程4-i18n动态国际化

    简介 本文是 Qml组件化编程 系列文章的第四篇 涛哥将教大家 如何在Qml中实现动态国际化 i18n 是 internationalization 国际化 的首尾字符加中间的 18 个字符 随着产品越做越大 要推向国际的时候 国际化这一步
  • C语言指针详解

    C语言指针详解 字符指针 1 如何定义 2 类型和指向的内容 3 代码例子 指针数组 1 如何定义 2 类型和内容 数组指针 1 如何定义 2 类型和指向类型 3 数组名vs 数组名 数组指针运用 数组参数 指针参数 一维数组传参 二维数组
  • 多级页表的优点和缺点

    多级页表是基于虚拟地址的分段来划分等级的 最低等级的页表上保存了最终的虚拟页号和物理页号的对应关系 例如拿32位的虚拟地址来说 如果页面的大小为4K 也就是12位 那么地址空间内将有20位 也就是1M的页表项目 每个项目对应一个虚拟页面 那
  • 机器学习2:朴素贝叶斯分类器Naïve Bayes Classifier(基于R language&Python)

    朴素贝叶斯是基于贝叶斯定理与特征条件独立假设的分类方法 朴素贝叶斯法与贝叶斯估计是不同的概念 对于给定的训练数据集 首先基于特征条件独立假设学习输入 输出的联合概率分布 然后基于此模型 对个给定的输入 x x x 利用贝叶斯定理求出后验概率
  • Unity基础篇:Unity2D图集(2):将剪裁好的图片导出。

    转载http blog csdn net hongyouwei article details 45011315 这位大佬讲的很好 但是他没有很好地考虑到我等小白的感受 故在此补充说明 1 在Unity的Project窗口下的Assets里
  • Kubernetes:全面了解 Deployment

    本文为作者的 Kubernetes 系列电子书的一部分 电子书已经开源 欢迎关注 电子书浏览地址 https k8s whuanle cn 适合国内访问 https ek8s whuanle cn gitbook Deployment 是
  • C语言练习

    大家好啊 我是一名职高的学生 即将面临就业 在就业和升本中选择了升本 这四年期间学的专业是计算机网络技术 第一年学过C语言也都忘得差不多了 这个暑假重新开始学的C语言并且从今天起开始写博客 下面这些题目是我在书上和一些资料上做的编程题 都是
  • HashMap、HashTable和Vector的存储扩容解析

    HashMap HashTable和Vector是面试时比较高频问到的知识点 今天就从三个的底层源码的角度分析三者之间的存储 扩容原理和异同点 HashMap 实现Map接口 实现原理 HashMap采用链地址法 即底层是一个数组实现 数组