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

Java基础与集合小压八股

Java基础与集合

HashMap 的底层结构是怎样的?JDK 1.7 和 1.8 有哪些区别?为什么要引入红黑树?(递进提问)

HashMap 底层是基于数组 + 链表 + 红黑树实现的。
在 JDK 1.7 中,它使用数组 + 链表的结构,采用头插法来解决哈希冲突;而从 JDK 1.8 开始,为了优化链表过长导致的查找性能下降问题,引入了红黑树,当链表长度超过 8 且数组长度超过 64 时,会将链表转换为红黑树。

同时,JDK 1.8 改用了尾插法,主要是为了解决多线程环境下扩容时可能出现的环形链表问题。

在索引计算上,JDK 1.8 对 hash 值做了高位扰动函数优化(即让当前 key 的 hashCode 与高十六位异或),来减少哈希冲突。

此外,扩容逻辑也更高效了,不再重新计算每个节点的哈希值,而是利用 (oldCap & hash) 判断节点在新表中的位置。(其实跟数组长度只能是 2 的倍数有关,触发扩容时,当前节点的新索引只需要+16。(n - 1) & hash)

HashMap 在什么情况下会将红黑树退化回链表?为什么要这么做?

当桶中链表长度超过 8 并且数组长度达到 64 时,会触发树化,将链表结构转为红黑树,以提升查找效率。(最坏情况下时间复杂度 O(n)->O(logn)

但当红黑树节点减小到 6 以下时,红黑树就会退化成链表。主要原因是红黑树节点结构复杂,占用更多内存。节点较少时,查找性能反而降低,得不偿失。

这里的阈值 6 和 8 是经过性能测试确定的经验值,保证在性能和内存之间的平衡性。(不选 7,因为会频繁树化和回退,性能开销大)

那如果在多线程环境下同时对 HashMap 进行 put 操作,会发生什么问题?你知道为什么 HashMap 在多线程下不安全吗?

在 JDK1.7 中,HashMap 在多线程下同时执行put方法,可能在 rehash 扩容过程中出现链表成环,导致死循环。

原因是 1.7 的扩容使用的头插法,rehash 扩容时多线程交错修改next指针可能导致节点反转出错。

1.8 时改用了尾插法,但他仍然是线程不安全的,因为多线程下同时put时仍可能出现**数据丢失(覆盖)、数据不可见(写入未同步)**等问题。

本就不应该在多线程环境下使用HashMap

你刚提到并发环境下要用 ConcurrentHashMap,那你能说一下它是如何保证线程安全的吗?

在 JDK1.7 中,ConcurrentHashMap使用Segment分段锁的方式实现线程安全,每个Segment内部使用ReentrantLock控制并发访问,不同Segment之间可以并行操作。相当于每个Segment对应一个HashMap

在 JDK1.8 中,使用类似HashMap的数组+链表+红黑树的结构,并通过 CAS+Synchronized+volitale 实现并发安全。

那如果在 ConcurrentHashMap 中执行 put 操作时,发生了哈希冲突,会经历哪些步骤?

ConcurrentHshMap在 JDK1.8 中会先通过 CAS 确保初始化,然后计算桶的位置。如果桶为空,那么使用 CAS 插入。如果发生冲突,则用 Synchronized 先锁住该桶,在链表或红黑树中插入该节点。从而保证线程安全。

讲讲 ArrayListLinkedList 的区别,它们在插入、查找时的时间复杂度分别是多少?

底层数据结构不同,ArrayList 是基于动态数组实现,元素在内存中连续存储。

LinkedList 是基于双向链表实现,元素在内存中不连续存储。

性能不同,ArrayList 中间插入的时间复杂度为 O(n),因为需要移动后续元素。查找时间复杂度只有 O(1)。LinkedList 插入的时间复杂度为 O(n),在首尾降为 O(1)。查找时间复杂度为 O(n),因为链表元素内存地址不连续。

equals()hashCode() 的关系是什么?为什么要同时重写?

如果两个对象根据 equals()相等,那么 hashCode()必须相等。反之,如果 hashcode()相等,不要求 equals()相等。在这种情况下,如果只修改 equals(),可能导致两个 equals()的对象的 hashCode() (散列值)不同,导致集合中包含两个元素,而不是一个。

说说 Java 的自动装箱和拆箱机制,有哪些容易出错的地方?

自动装箱是指 Java 编译器自动将基本数据类型转换为对应的包装类型,比如int转为Integer类型。

自动拆箱是指 Java 编译器自动将包装类型转换为对应的基本数据类型,比如Integer转为int类型

包装类对象可能为 null,如果直接拆箱,可能会NPE

在循环或者高性能场景,频繁拆箱和装箱可能导致性能开销。

http://www.dtcms.com/a/528819.html

相关文章:

  • 网站建设做网站需要多少钱?杭州网站建设公司有哪些
  • [ Redis ] SpringBoot集成使用Redis(补充)
  • GitHub等平台形成的开源文化正在重塑伊朗人
  • 贵州省建设厅网站造价工程信息网东港建站公司
  • UE5 蓝图-17:主 mainUI 界面蓝图,构成与尺寸分析;界面菜单栏里按钮 Ul_menuButtonsUl 蓝图的构成记录,
  • 公司企业网站免费建设网站建设需要技术
  • SQL MID() 函数详解
  • SQL187 每份试卷每月作答数和截止当月的作答总数。
  • 三河建设局网站做学校网站用什么模版
  • 装修网站建设服务商wordpress 编辑图片无法显示
  • 建设网站要求有哪些营销型网站建设搭建方法
  • jQuery noConflict() 方法详解
  • JavaScript 性能优化系列(六)接口调用优化 - 6.4 错误重试策略:智能重试机制,提高请求成功率
  • 绘画基础知识学习
  • 自己的服务器做网站要备案做网站用到ps么
  • 第 4 篇:SSM 分布式落地:状态持久化与并行状态(含 Redis/MySQL 实战)
  • STM32全栈智慧鱼缸——硬件选型、接线图、软件流程图与完整源码
  • 【11408学习记录】考研数学概率论攻坚:事件的独立性与独立重复试验核心精讲
  • linux下文件操作函数
  • 电商网站建设与维护意味着什么公众号登录怎么退出
  • 专业的营销型网站培训中心wordpress 美化网站
  • 【Java数据结构】——常见力扣题综合
  • 网站长期建设运营计划书江门营销网站建设
  • ProcDump 学习笔记(6.7):监视异常(未处理/首机会/消息过滤/进程终止)
  • C++编程实践——Linux下的CPU控制
  • NTRU 公钥加密系统详解
  • 深入浅出 VGGNet:经典卷积神经网络解析
  • 盐城整站优化柳州做网站去哪家公司好
  • 协程:实战与系统集成(高级篇)
  • 芯片验证基石UVM:高效验证的方法论与挑战