Java 集合框架大师课:集合框架源码解剖室(五)

🔥Java 集合框架大师课:集合框架源码解剖室(五)

💣 警告:本章包含大量 裸码级硬核分析,建议搭配咖啡因饮料阅读!☕️


第一章 ArrayList 的扩容玄学

1.1 动态扩容核心代码大卸八块

// 祖师爷の扩容魔法 ✨
private Object[] grow(int minCapacity) {int oldCapacity = elementData.length;// 1.5倍增长公式(暗藏数学之美)int newCapacity = oldCapacity + (oldCapacity >> 1); return elementData = Arrays.copyOf(elementData, newCapacity);
}

📌 灵魂拷问表

现象数学原理性能影响
初始容量102的倍数+2?🤔小数据集省内存
1.5倍增长斐波那契数列逼近 🌊平衡内存与扩容次数
Arrays.copyOf内存连续分配 📏超大数组扩容卡顿风险

1.2 扩容流程可视化

在这里插入图片描述


第二章 HashMap 的哈希战争

2.1 扰动函数の黑科技

static final int hash(Object key) {int h;// 让高位参与哈希运算,减少碰撞 💥return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

🎯 哈希碰撞处理方案对比

方案数据结构时间复杂度JDK版本
链表法单向链表 🚂O(n)<8
红黑树平衡二叉树 🌳O(logn)≥8
开放寻址线性探测 🔍O(1)~O(n)其他实现

2.2 树化阈值背后的博弈

// 链表转红黑树的临界点
static final int TREEIFY_THRESHOLD = 8;// 为什么是8?统计学の魔法 🎲
/*
* 理想哈希下链表长度出现8的概率:0.00000006
* 此时树化的收益超过维护成本
*/

第三章 LinkedList 的双向暗恋

3.1 节点结构解剖图

private static class Node<E> {E item;          // 当前元素 🎁Node<E> next;    // 下个节点 👉Node<E> prev;    // 上个节点 👈
}

📊 增删操作性能真相

操作ArrayListLinkedList真相大白 😏
头部插入O(n)O(1)LinkedList胜
随机删除O(n)O(1)但需要先遍历找节点!😱
尾部追加O(1)O(1)平手 👯

3.2 迭代器陷阱演示

LinkedList<Integer> list = new LinkedList<>();
list.addAll(Arrays.asList(1,3,5,7,9));// 错误示范:用for循环随机访问
for(int i=0; i<list.size(); i++){list.get(i); // O(n^2) 警告!💣
}// 正确姿势:迭代器访问
Iterator<Integer> it = list.iterator();
while(it.hasNext()){it.next(); // O(n) 丝滑访问 🛷
}

第四章 ConcurrentHashMap 的线程安全秘籍

4.1 📌 锁机制对比表

版本数据结构锁粒度吞吐量提升
JDK7Segment 数组16个独立分区 🔒4~6倍
JDK8Node+CAS单个链表头 🔓10倍+
JDK19协程+无锁无锁访问 🚀实验阶段

4.2 size() 方法の统计学魔术

// 高并发下的size计算策略
public int size() {long n = sumCount();return ((n < 0L) ? 0 : (n > (long)Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int)n);
}// 分片计数减少竞争 🎯
final long sumCount() {CounterCell[] as = counterCells; long sum = baseCount;if (as != null) {for (CounterCell a : as)if (a != null)sum += a.value;}return sum;
}

4.3 putVal() 方法源码拆解

final V putVal(K key, V value, boolean onlyIfAbsent) {// 哈希扰动加强版 🌪️int hash = spread(key.hashCode());int binCount = 0;for (Node<K,V>[] tab = table;;) {Node<K,V> f; int n, i, fh;if (tab == null || (n = tab.length) == 0)tab = initTable(); // 延迟初始化else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {if (casTabAt(tab, i, null, new Node<>(hash, key, value)))break; // CAS 无锁插入成功!}else if ((fh = f.hash) == MOVED)tab = helpTransfer(tab, f); // 协助扩容else {// 真正的锁竞争区 💥synchronized (f) {if (tabAt(tab, i) == f) {// 链表/红黑树插入逻辑...}}}}addCount(1L, binCount);return null;
}

🎯 关键操作流程图

在这里插入图片描述


🔥 性能调优黄金法则

// ArrayList 最佳实践
List<String> list = new ArrayList<>(100_0000); // 预分配容量 🚀// HashMap 防坑指南
Map<String,Object> map = new HashMap<>(32, 0.75f); // 控制负载因子 ⚖️// LinkedList 使用禁区
if(需要随机访问) {throw new IllegalArgumentException("别用我!"); 💣
}

第五章 LinkedHashMap 的时空穿梭术

5.1 双向链表结构大曝光

// 继承自 HashMap.Node 的超级节点 🦸
static class Entry<K,V> extends HashMap.Node<K,V> {Entry<K,V> before, after; // 时空隧道入口 🕳️Entry(int hash, K key, V value, Node<K,V> next) {super(hash, key, value, next);}
}// 维护访问顺序的核心代码 🔗
void afterNodeAccess(Node<K,V> e) {Entry<K,V> last;if (accessOrder && (last = tail) != e) {// 把最近访问的节点移动到链表尾部Entry<K,V> p = (Entry<K,V>)e, b = p.before, a = p.after;p.after = null;if (b == null)head = a;elseb.after = a;if (a != null)a.before = b;elselast = b;if (last == null)head = p;else {p.before = last;last.after = p;}tail = p;++modCount;}
}

5.2 LRU 缓存实现原理

// 实现简易 LRU 缓存 🗂️
public class LRUCache<K,V> extends LinkedHashMap<K,V> {private final int maxCapacity;public LRUCache(int maxCapacity) {super(maxCapacity, 0.75f, true);this.maxCapacity = maxCapacity;}@Overrideprotected boolean removeEldestEntry(Map.Entry<K,V> eldest) {return size() > maxCapacity; // 自动淘汰最旧元素 🗑️}
}// 使用示例:
LRUCache<String, User> cache = new LRUCache<>(1000);
cache.put("user_9527", user); // 插入新数据
cache.get("user_1234");       // 访问数据会提升新鲜度

第六章 PriorityQueue 的堆排序魔法

6.1 最小堆实现原理

// 优先队列的骨架数组结构 🦴
transient Object[] queue; // 元素插入时的上浮操作 🌊
private void siftUp(int k, E x) {if (comparator != null)siftUpUsingComparator(k, x);elsesiftUpComparable(k, x);
}private void siftUpComparable(int k, E x) {Comparable<? super E> key = (Comparable<? super E>) x;while (k > 0) {int parent = (k - 1) >>> 1; // 找父节点位置Object e = queue[parent];if (key.compareTo((E) e) >= 0)break;queue[k] = e; // 父节点下沉k = parent;}queue[k] = key;
}

📊 堆操作复杂度表

操作时间复杂度原理说明
插入元素O(logn)上浮操作调整堆结构 🌊
取出队首O(logn)下沉操作重建堆结构 ⚓
查看队首O(1)直接返回堆顶元素 🏔️
批量建堆O(n)Floyd 算法优化 🚀

6.2 堆结构可视化

在这里插入图片描述


🛠️ 手撕源码挑战赛

挑战一:ConcurrentHashMap 扩容触发器

// 找出触发扩容的隐藏条件
private final void addCount(long x, int check) {// 当 counterCells 不为空时...if (check >= 0) {Node<K,V>[] tab, nt; int n, sc;while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&(n = tab.length) < MAXIMUM_CAPACITY) {// 神秘扩容信号 🚨int rs = resizeStamp(n);if (sc < 0) {if ((sc >>> RESIZE_STAMP_SHIFT) != rs || sc == rs + 1 ||sc == rs + MAX_RESIZERS || (nt = nextTable) == null ||transferIndex <= 0)break;if (U.compareAndSwapInt(this, SIZECTL, sc, sc + 1))transfer(tab, nt);}// 尝试发起扩容的线程会走到这里 💪else if (U.compareAndSwapInt(this, SIZECTL, sc,(rs << RESIZE_STAMP_SHIFT) + 2))transfer(tab, null);s = sumCount();}}
}

挑战二:PriorityQueue 堆排序缺陷

// 危险操作:直接修改队列元素
PriorityQueue<Student> queue = new PriorityQueue<>();
queue.add(new Student("Alice", 90));
queue.add(new Student("Bob", 80));// 作死修改分数导致堆结构破坏 💣
queue.peek().score = 100; 
System.out.println(queue.poll()); // 输出结果可能不符合预期!// 正确做法:删除后重新插入
Student s = queue.poll();
s.score = 100;
queue.offer(s);

🧘♂️ 下期预告:《集合框架的暗黑料理——弱引用与幽灵队列》👻

// 彩蛋代码:HashMap 的隐藏迭代器
final class KeyIterator extends HashIterator implements Iterator<K>, Spliterator<K> {public final K next() { return nextNode().key; }
}
// 快速失败(fail-fast)机制的实现秘密 🔍

🌟 终极领悟 :读源码就像破案,每个设计都是权衡的艺术!下次面试被问HashMap原理时,请优雅地甩出红黑树阈值计算公式 🌈

// 彩蛋:HashMap 树化阈值计算公式
static final int TREEIFY_THRESHOLD = 8;
// 为什么是8?因为 log8 = 3, 在O(logn)和O(n)之间找到平衡点 ⚖️

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/31617.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Kubernetes服务部署 —— Kafka

1、简介 Kafka和zookeeper是两种典型的有状态的应用集群服务。首先kafka和zookeeper都需要存储盘来保存有状态信息&#xff1b;其次kafka和zookeeper每一个实例都需要有对应的实例Id (Kafka需broker.id, zookeeper需要my.id) 来作为集群内部每个成员的标识&#xff0c;集群内节…

计算机网络基础知识

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/literature?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;…

电脑的写字板如何使用?

打开写字板&#xff1a; 直接按一下键盘上的win R 键&#xff0c;然后输入&#xff1a;write &#xff0c; 再按一下回车 , 即可打开写字板 可以在里面写文字 和 插入图片等… &#xff0c; 如下所示&#xff1a; 保存写字板内容&#xff1a; 当我们写好了之后&#xff0c;…

用vector实现栈的功能

要注意pop_back和back()的区别 #include <bits/stdc.h> using namespace std;void Push(vector<int> &v,int x) {v.push_back(x); }void Top(vector<int> &v) {if(!v.empty()){cout<<v.back()<<endl;// v.pop_back();}else {cout<&l…

SegMAN模型详解及代码复现

SegMAN模型概述 模型背景 在深入探讨SegMAN模型之前&#xff0c;我们需要了解其研究背景。在SegMAN出现之前&#xff0c;计算机视觉领域的研究主要集中在以下几个方面&#xff1a; 手工制作方法&#xff0c;如SIFT基于卷积神经网络(CNN)的方法&#xff0c;如STN和PTN对平移、…

基于粒子群算法的配电网重构

一、配电网重构原理 定义&#xff1a; 配电网重构是指在满足运行约束的前提下&#xff0c;通过改变开关状态优化配电网性能&#xff0c;提高系统的经济效益和运行效率。 拓扑约束&#xff1a; 配电网必须保持径向拓扑&#xff0c;避免环网或孤岛。采用算法控制开关状态的选择&…

自然语言处理:无监督朴素贝叶斯模型

介绍 大家好&#xff0c;博主又来和大家分享自然语言处理领域的知识了&#xff0c;今天给大家介绍的是无监督朴素贝叶斯模型。 在自然语言处理这个充满挑战又极具魅力的领域&#xff0c;如何从海量的文本数据中挖掘有价值的信息&#xff0c;一直是研究者们不断探索的课题。无…

软件工程概述

软件开发生命周期 软件定义时期&#xff1a;包括可行性研究和详细需求分析&#xff0c;任务是确定软件开发的总目标。 问题定义可行性研究&#xff08;经济、技术、操作、社会可行性&#xff0c;确定问题和解决办法&#xff09;需求分析&#xff08;确定功能需求&#xff0c;性…

基于51单片机的日历流水灯proteus仿真

地址&#xff1a; https://pan.baidu.com/s/1lt1ubDhKNTeIcP0Kf1UXrA 提取码&#xff1a;1234 仿真图&#xff1a; 芯片/模块的特点&#xff1a; AT89C52/AT89C51简介&#xff1a; AT89C51 是一款常用的 8 位单片机&#xff0c;由 Atmel 公司&#xff08;现已被 Microchip 收…

【Go沉思录】朝花夕拾:探究 Go 接口型函数

本文目录 序1.接口型函数案例方式1 GetterFunc 类型的函数作为参数方式2 实现了 Getter 接口的结构体作为参数价值 2.net/http包中的使用场景 序 之前写Geecache的时候&#xff0c;遇到了接口型函数&#xff0c;当时没有搞懂&#xff0c;现在重新回过头研究复习Geecache的时候…

【若依框架】代码生成详细教程,15分钟搭建Springboot+Vue3前后端分离项目,基于Mysql8数据库和Redis5,管理后台前端基于Vue3和Element Plus,开发小程序数据后台

今天我们来借助若依来快速的搭建一个基于springboot的Java管理后台&#xff0c;后台网页使用vue3和 Element Plus来快速搭建。这里我们可以借助若依自动生成Java和vue3代码&#xff0c;这就是若依的强大之处&#xff0c;即便你不会Java和vue开发&#xff0c;只要跟着石头哥也可…

Java 线程与线程池类/接口继承谱系图+核心方法详解

Java 线程与线程池类/接口继承谱系图 1. 线程相关类与接口关系 #mermaid-svg-shTOx2cIkm79Zevf {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-shTOx2cIkm79Zevf .error-icon{fill:#552222;}#mermaid-svg-shTOx2cI…

BFS(十三)463. 岛屿的周长

463. 岛屿的周长 给定一个 row x col 的二维网格地图 grid &#xff0c;其中&#xff1a;grid[i][j] 1 表示陆地&#xff0c; grid[i][j] 0 表示水域。 网格中的格子 水平和垂直 方向相连&#xff08;对角线方向不相连&#xff09;。整个网格被水完全包围&#xff0c;但其中恰…

使用 Ansys Mechanical 和 optiSLang 进行材料模型校准

介绍 提供与实验数据匹配的准确仿真结果的材料模型是成功对实际应用进行 FEA 仿真的基础。根据实验数据校准材料模型是一个优化问题&#xff0c;其中仿真和真值信号之间的“距离”最小&#xff0c;表明模型与实验的“接近”程度。在此示例中&#xff0c;我们将对校准示例进行概…

SSA-朴素贝叶斯分类预测matlab代码

麻雀搜索算法&#xff08;Sparrow Search Algorithm&#xff0c;简称 SSA&#xff09;是于 2020 年提出的一种新兴群智能优化算法&#xff0c;其灵感主要来源于麻雀的觅食行为以及反捕食行为。 本次使用的数据是 Excel 格式的分类数据集数据。数据集被合理划分为训练集、验证集…

Houdini SOP层 Scatter节点

SOP 代表 Surface Operator&#xff08;几何体操作节点&#xff09;&#xff0c;所有几何体的建模、变形、分布等操作都在此层级完成。 Scatter节点的作用就是 以不同的密度在模型表面撒点 Scatter 节点属于 SOP&#xff08;几何体&#xff09;层级&#xff1a; 进入 Geometr…

数据结构:有序表的合并

前文介绍了《有序表的插入》&#xff0c;本文介绍有序表的合并。这两种对有序表的操作&#xff0c;是数据结构中常考的内容&#xff0c;特别是在 408 考卷中&#xff0c;在算法设计的题目中&#xff0c;有可能会考查对有序表的操作。那么&#xff0c;这两篇文章中的方法就是能够…

STM32Cubemx-H7-8-维特科技WT61C-TTL陀螺仪获取XYZ角度

前言 本人玩车的时候要用到陀螺仪 MPU6050容易卡死&#xff0c;然后还很漂&#xff0c;还是太难用了 68块钱的陀螺仪再上位机上的效果挺满意&#xff0c;于是打算用串口用到自己的模型上 本文教大家如何编写串口程序&#xff0c;通过串口获取角度 大家把本文的原理学会后&…

本地部署Navidrome个人云音乐平台随时随地畅听本地音乐文件

文章目录 前言1. 安装Docker2. 创建并启动Navidrome容器3. 公网远程访问本地Navidrome3.1 内网穿透工具安装3.2 创建远程连接公网地址3.3 使用固定公网地址远程访问 前言 今天我要给大家安利一个超酷的私有化音乐神器——Navidrome&#xff01;它不仅让你随时随地畅享本地音乐…

音视频入门基础:RTP专题(15)——FFmpeg源码中,获取RTP的视频信息的实现

一、引言 通过FFmpeg命令可以获取到SDP文件描述的RTP流的视频压缩编码格式、色彩格式&#xff08;像素格式&#xff09;、分辨率、帧率信息&#xff1a; ffmpeg -protocol_whitelist "file,rtp,udp" -i XXX.sdp 本文以H.264为例讲述FFmpeg到底是从哪个地方获取到这…