面试官:为什么HashMap 使用的时候指定容量?






面试官:百万数据的导入导出解决方案,怎么设计?

以下正文:

前言


其实可以看到我写了这么久的博客,很少去写hashMap的东西。

为什么?因为这个东西感觉是java面试必备的,我感觉大家都看到腻了,所以一直没怎么去写hashMap相关的。

ps:之前整理过一个hashmap存值的流程图,感觉够了,因为put过程基本可以把所有核心点都过一遍。

今天为什么我突然要来写这一篇文章,因为最近在公司看一些老项目代码,我才发现原来其实很多人都没用对。

本篇内容:

  • 举例说明 HashMap 使用的时候指定容量 错误用法;
  • 源码走读,HashMap初始容量的 计算方式;
  • 源码走读扩容的点;
  • 正确应该怎么去用,一定要理解再用;
  • 一些杂谈。

正文
不开玩笑,真的都知道指定容量,但是有些用对了,有些没用对。


为什么要指定容量?


这个原由,都不用说,阿里的java开发手册就说的很明白:

其实核心点,就是避免数据量慢慢增加,导致反复触发扩容,影响性能。

于是乎就很多错误的使用方式了(虽热影响不大):

错误理解使用示例 ① :

分页查询出来的数据,需要转换成 Map, 因为分页是固定了一页最多15条。

所以出现了这个代码:

Map<String, String> map = new HashMap<>(15);

或者是

Map<String, String> map = new HashMap<>(userPageList.size());
错误理解使用示例 ② :

类型type 有 4种, 要放到一个map里面,返回去。

所以出现了这个代码:

Map<Integer, String> map = new HashMap<>(4);
错误理解使用示例 ③:

一个参数map,里面想放2个参数。

所以出现了这个代码:

Map<String, String> map = new HashMap<>(2);

不多举例,其实这几个错误示例,都是错在指定容量的 值上。

默认 指定是 传入 16, 16* 0.75=12 , 所以扩容阈值是12 。

说到这里,大家应该知道为什么上面是错误用法了吧?

比如我们想 存 4个元素到Map, 我们为了避免后面触发扩容影响性能(其实元素少性能没多少影响), 就指定了 4 :

Map<Integer, String> map = new HashMap<>(4);

其实这样 4x0.75= 3 ,那么如果存放第四个元素的时候,就会触发扩容

这样就是违背了我们开始指定 的 4 的最初用意。

实战看看这个错误使用场景的情况:

同过反射,将capacity属性的权限拿到,可以直接打印出来看下capacity的变化,就知道是否触发了扩容:

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

    Map<String, String> map = new HashMap<>(4);
    Class<?> mapType = map.getClass();
    Method capacity = mapType.getDeclaredMethod("capacity");
    capacity.setAccessible(true);

    map.put("1""第一个元素插入");
    System.out.println("capacity : " + capacity.invoke(map) + "    size : " + map.size());
    map.put("2""第二个元素插入");
    System.out.println("capacity : " + capacity.invoke(map) + "    size : " + map.size());
    map.put("3""第三个元素插入");
    System.out.println("capacity : " + capacity.invoke(map) + "    size : " + map.size());
    map.put("4""第四个元素插入");
    System.out.println("capacity : " + capacity.invoke(map) + "    size : " + map.size());

}

看下打印效果:

为什么,当size =3 ,也就是插入三个元素的时候还没变。

因为我们初始化容量值传入的 4,  4* 0.75 =3. 扩容阈值是 3!

当插入第四个元素的时候, 就超过了扩容阈值,所以触发了扩容,所以看的最后其实是进行了一次扩容,打印出来的capacity是 8.

那么我们应该传多少?

4/0.75  + 1 = 6.3333333

我们指定传6么?还是传 7 ?

指定6:

指定7:

指定6,7 都没区别好像, 值得庆祝的是,没有再次触发扩容。

那么为啥没区别呢?

HashMap会转换成大于该capacity 的第一个2的幂作为容量 。

所以传5,6,7,8 都是 8 ;

传9,10,11,12,13,14,15,16 都是 16 ;

好了不多啰嗦了, 最后再补一嘴, 默认指定容量,其实就是 内存换性能

所以真正去使用指定容量的时候, 需要考虑:如果我是一个定时任务,允许跑1小时。。。我需要考虑性能么?

或者如果我服务内存很小,我是不是要对内存省吃俭用?







END

1.为什么阿里巴巴修正了HashMap关于1024个元素扩容的次数?(典藏版)2.为什么阿里不推荐使用 keySet() 遍历HashMap?3.HashMap 面试关键6连问,你能扛得住吗?4.多线程环境下,HashMap为什么会出现死循环?

我是技术程管家,专心做内容,不割韭菜

分享技术成长之路,不忘初心,惠泽他人终身学习,与时俱进,点赞关注不迷路

相关推荐

  • 面试官:你说说 Mysql 索引失效有哪些场景?
  • 上海一对夫妻自爆现状:老公失业被裁,老婆宁愿净身出户也要离婚,房贷欠100多万,存款接近0,这日子怎么过下去......
  • 21 世纪的工作方法论:工作八正道
  • 分享几款超好用的JVM调优工具,建议收藏!
  • OpenAI CEO Sam Altman 和COO Brad 最新精彩联合访谈 · 完整版+视频
  • [开源]一个开源的多端即时聊天工具,快速建立企业内部通讯系统
  • 斩获WSDM 2024冠军方案!
  • 图解 ElasticSearch 搜索原理
  • 每日prompt:女战士
  • AI延时视频生成工具MagicTime可以在线体验了
  • 大数据、数据架构、推荐冷启动...小红书的 AI 数据新方案都在这个会
  • Spring Boot集成easypoi快速入门Demo
  • 人人都该知道的12个赚钱底层思维;裸辞一年,自媒体收益百万丨生财有术
  • 通过JS获取你当前的网络状况?建议大家学一学~
  • 国内行情差,来看看国外
  • 我们真的需要把训练集的损失降到零吗?
  • 从启发式到模型化 京东推荐广告排序机制演化
  • 全平台GUI库, 物联网,嵌入式,单片机,桌面应用都行
  • 6.2K Star很精美,一个跨平台的聊天软件
  • 数据科学中10个常用的高级SQL查询方法