296 字
1 分钟
Java 常见集合与底层源码面试题解析(List / Map / HashMap)
Java集合框架

复杂度
时间复杂度







空间复杂度

总结

List

数组







ArrayList源码分析

成员变量

构造方法

添加数据

第2到10次添加数据都不会扩容
扩容即,将数组长度添加到原来的1.5倍
题目
底层实现原理

有参构造函数扩容问题

如何实现List和数组的转换

asList方法只涉及了对象的引用,不涉及对象的创建,因此修改数组也会影响列表
toArray方法则是复制一份,修改List不会影响数组
ArrayList与LinkedList区别
单向链表




双向链表


链表对比

回答




Map

二叉树
原理






总结

红黑树
原理



总结

散列表
原理







链表太长会导致查询效率变为O(n),通过将链表转换为红黑树解决


总结

说一下HashMap的实现原理
### 原理

追问:jdk1.8和jdk1.7的hashmap实现有什么区别

回答

HashMap的put方法具体流程

源码分析


添加数据流程图


源码
public V put(K key, V value) { return putVal(hash(key), key, value, false, true);}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { Node<K,V>[] tab; Node<K,V> p; int n, i; //判断数组是否未初始化 if ((tab = table) == null || (n = tab.length) == 0) //如果未初始化,调用resize方法 进行初始化 n = (tab = resize()).length; //通过 & 运算求出该数据(key)的数组下标并判断该下标位置是否有数据 if ((p = tab[i = (n - 1) & hash]) == null) //如果没有,直接将数据放在该下标位置 tab[i] = newNode(hash, key, value, null); //该数组下标有数据的情况 else { Node<K,V> e; K k; //判断该位置数据的key和新来的数据是否一样 if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) //如果一样,证明为修改操作,该节点的数据赋值给e,后边会用到 e = p; //判断是不是红黑树 else if (p instanceof TreeNode) //如果是红黑树的话,进行红黑树的操作 e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value); //新数据和当前数组既不相同,也不是红黑树节点,证明是链表 else { //遍历链表 for (int binCount = 0; ; ++binCount) { //判断next节点,如果为空的话,证明遍历到链表尾部了 if ((e = p.next) == null) { //把新值放入链表尾部 p.next = newNode(hash, key, value, null); //因为新插入了一条数据,所以判断链表长度是不是大于等于8 if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st //如果是,进行转换红黑树操作 treeifyBin(tab, hash); break; } //判断链表当中有数据相同的值,如果一样,证明为修改操作 if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k)))) break; //把下一个节点赋值为当前节点 p = e; } } //判断e是否为空(e值为修改操作存放原数据的变量) if (e != null) { // existing mapping for key //不为空的话证明是修改操作,取出老值 V oldValue = e.value; //一定会执行 onlyIfAbsent传进来的是false if (!onlyIfAbsent || oldValue == null) //将新值赋值当前节点 e.value = value; afterNodeAccess(e); //返回老值 return oldValue; } } //计数器,计算当前节点的修改次数 ++modCount; //当前数组中的数据数量如果大于扩容阈值 if (++size > threshold) //进行扩容操作 resize(); //空方法 afterNodeInsertion(evict); //添加操作时 返回空值 return null;}回答

HashMap扩容机制
流程图

回答

HashMap寻址算法




HashMap死循环问题



分享
如果这篇文章对你有帮助,欢迎分享给更多人!
Java 常见集合与底层源码面试题解析(List / Map / HashMap)
https://xinrose.top/posts/interview/java-collections/ 部分信息可能已经过时
相关文章 智能推荐
1
Java 框架篇面试题:Spring、Spring Boot 与 MyBatis 核心解析
面试 全面解析 Spring 单例 Bean 线程安全、AOP 实践、声明式事务及失效场景、Bean 生命周期、三级缓存循环依赖、Spring Boot 自动配置与启动流程、MyBatis 延迟加载与缓存机制。
2
JVM 面试题核心汇总与实战解析
面试 全面整理 JVM 核心面试题:JVM 内存组成(堆、栈、方法区/元空间)、类加载机制与双亲委派、垃圾回收算法与 GC 收集器、JVM 调优参数与 OOM/CPU 飙高排查思路。
3
Java 常见业务与高频技术场景面试题汇总
面试 全面整理 Java 开发高频技术场景与实战面试题:单点登录(SSO/JWT)、RBAC 权限认证、数据与文件上传安全、ELK 日志采集与排查、Linux 运维命令、Arthas 生产问题排查与系统性能瓶颈调优。
4
Java 常用设计模式核心解析与实战
面试 全面整理 Java 常用设计模式核心面试题:工厂模式(简单工厂、工厂方法、抽象工厂)、策略模式、责任链模式等核心 UML 结构、演进思路、优缺点分析与业务落地场景。
5
Java 多线程与并发编程核心面试题精讲
面试 深入剖析线程与进程、线程状态机与生命周期、wait/sleep/notify、Synchronized 锁升级原理(偏向锁/轻量级锁/重量级锁与 MarkWord)、JMM 内存模型、CAS 与原子操作。