当前位置: 首页 > news >正文

每日五道java面试题之java基础篇(七)

在这里插入图片描述

第一题. HashMap和HashTable有什么区别?其底层实现是什么?

区别

  1. HashMap⽅法没有synchronized修饰,线程⾮安全,HashTable线程安全;
  2. HashMap允许key和value为null,⽽HashTable不允许

底层实现:数组+链表实现,jdk8开始链表⾼度到8、数组⻓度超过64,链表转变为红⿊树,元素以内部类Node节点存在
3. 计算key的hash值,⼆次hash然后对数组⻓度取模,对应到数组下标,
4. 如果没有产⽣hash冲突(下标位置没有元素),则直接创建Node存⼊数组,
5. 如果产⽣hash冲突,先进⾏equal⽐较,相同则取代该元素,不同,则判断链表⾼度插⼊链表,链表⾼度达到8,并且数组⻓度到64则转变为红⿊树,⻓度低于6则将红⿊树转回链表
6. key为null,存在下标0的位置

第二题.谈谈ConcurrentHashMap的扩容机制

1.7版本

  1. 1.7版本的ConcurrentHashMap是基于Segment分段实现的
  2. 每个Segment相对于⼀个⼩型的HashMap
  3. 每个Segment内部会进⾏扩容,和HashMap的扩容逻辑类似
  4. 先⽣成新的数组,然后转移元素到新数组中
  5. 扩容的判断也是每个Segment内部单独判断的,判断是否超过阈值

1.8版本

  1. 1.8版本的ConcurrentHashMap不再基于Segment实现
  2. 当某个线程进⾏put时,如果发现ConcurrentHashMap正在进⾏扩容那么该线程⼀起进⾏扩容
  3. 如果某个线程put时,发现没有正在进⾏扩容,则将key-value添加到ConcurrentHashMap中,然后判断是否超过阈值,超过了则进⾏扩容
  4. ConcurrentHashMap是⽀持多个线程同时扩容的
  5. 扩容之前也先⽣成⼀个新的数组
  6. 在转移元素时,先将原数组分组,将每组分给不同的线程来进⾏元素的转移,每个线程负责⼀组或多组的元素转移⼯作

第三题. Jdk1.7到Jdk1.8 HashMap 发⽣了什么变化(底层)?

  1. 1.7中底层是数组+链表,1.8中底层是数组+链表+红⿊树,加红⿊树的⽬的是提⾼HashMap插⼊和查询整体效率
  2. 1.7中链表插⼊使⽤的是头插法,1.8中链表插⼊使⽤的是尾插法,因为1.8中插⼊key和value时需要判断链表元素个数,所以需要遍历链表统计链表元素个数,所以正好就直接使⽤尾插法
  3. 1.7中哈希算法⽐较复杂,存在各种右移与异或运算,1.8中进⾏了简化,因为复杂的哈希算法的⽬的就是提⾼散列性,来提供HashMap的整体效率,⽽1.8中新增了红⿊树,所以可以适当的简化哈希算法,节省CPU资源

第四题. 说⼀下HashMap的Put⽅法

先说HashMap的Put⽅法的⼤体流程:

  1. 根据Key通过哈希算法与与运算得出数组下标
  2. 如果数组下标位置元素为空,则将key和value封装为Entry对象(JDK1.7中是Entry对象,JDK1.8中
    是Node对象)并放⼊该位置
  3. 如果数组下标位置元素不为空,则要分情况讨论
  • 如果是JDK1.7,则先判断是否需要扩容,如果要扩容就进⾏扩容,如果不⽤扩容就⽣成Entry
    对象,并使⽤头插法添加到当前位置的链表中
  • 如果是JDK1.8,则会先判断当前位置上的Node的类型,看是红⿊树Node,还是链表Node
    • 如果是红⿊树Node,则将key和value封装为⼀个红⿊树节点并添加到红⿊树中去,在这个
      过程中会判断红⿊树中是否存在当前key,如果存在则更新value
    • 如果此位置上的Node对象是链表节点,则将key和value封装为⼀个链表Node并通过尾插法插⼊到链表的最后位置去,因为是尾插法,所以需要遍历链表,在遍历链表的过程中会判断是否存在当前key,如果存在则更新value,当遍历完链表后,将新链表Node插⼊到链表中,插⼊到链表后,会看当前链表的节点个数,如果⼤于等于8,那么则会将该链表转成红⿊树
    • 将key和value封装为Node插⼊到链表或红⿊树中后,再判断是否需要进⾏扩容,如果需要就扩容,如果不需要就结束PUT⽅法

第五题. HashMap的扩容机制原理

1.7版本

  1. 先⽣成新数组
  2. 遍历⽼数组中的每个位置上的链表上的每个元素
  3. 取每个元素的key,并基于新数组⻓度,计算出每个元素在新数组中的下标
  4. 将元素添加到新数组中去
  5. 所有元素转移完了之后,将新数组赋值给HashMap对象的table属性

1.8版本

  1. 先⽣成新数组
  2. 遍历⽼数组中的每个位置上的链表或红⿊树
  3. 如果是链表,则直接将链表中的每个元素重新计算下标,并添加到新数组中去
  4. 如果是红⿊树,则先遍历红⿊树,先计算出红⿊树中每个元素对应在新数组中的下标位置
    a. 统计每个下标位置的元素个数
    b. 如果该位置下的元素个数超过了8,则⽣成⼀个新的红⿊树,并将根节点的添加到新数组的对应位置
    c. 如果该位置下的元素个数没有超过8,那么则⽣成⼀个链表,并将链表的头节点添加到新数组的对应位置
  5. 所有元素转移完了之后,将新数组赋值给HashMap对象的table属性

如果我的内容对你有帮助,请点赞,评论,收藏。创作不易,大家的支持就是我坚持下去的动力!

在这里插入图片描述

http://www.lryc.cn/news/299730.html

相关文章:

  • 树莓派4B(Raspberry Pi 4B)使用docker搭建单机版nacos [基于docker-compose]
  • DAY50:完全背包、爬楼梯、322、279
  • MySQL性能调优篇(3)-缓存的优化与清理
  • Zig、C、Rust的Pk1
  • 如何用 ChatGPT 做项目管理?
  • DS:树及二叉树的相关概念
  • MATLAB | 情人节画个花瓣venn图?
  • [日常使用] Shell常用命令
  • QT+OSG/osgEarth编译之八十七:osgdb_p3d+Qt编译(一套代码、一套框架,跨平台编译,版本:OSG-3.6.5插件库osgdb_p3d)
  • 寒假 day13
  • 探索微信小程序的奇妙世界:从入门到进阶
  • 容器库(4)-std::forward_list
  • Netty Review - 服务端channel注册流程源码解析
  • 冒泡排序平均需要跑多少趟:拉马努金Q函数初探
  • Shell 学习笔记(三)-shell变量
  • 新冠:2022和2024两次新冠感染的对比
  • 笔记:《NCT全国青少年编程能力等级测试教程Python语言编程二级》
  • 顶级思维方式——认知篇五(思想的觉醒)
  • 面试技术栈 —— 2024网易雷火暑期实习真题
  • 【小赛1】蓝桥杯双周赛第5场(小白)思路回顾
  • docker (二)-yum二进制部署
  • 【深度学习】S2 数学基础 P2 线性代数(下)
  • 【软考高级信息系统项目管理师--考试内容大纲篇】
  • C语言——枚举类型
  • linux---内存管理
  • v-model原理
  • 波奇学Linux:文件系统
  • 项目访问量激增该如何应对
  • 【Linux环境基础开发工具的使用(yum、vim、gcc、g++、gdb、make/Makefile)】
  • 幻兽帕鲁官方更新了,服务器端怎么更新?