Java ArrayList vs LinkedList:一场“链表”和“数组”的街头巷战
Java ArrayList vs LinkedList:一场“链表”和“数组”的街头巷战
大家好啊!今天想和你们聊聊 ArrayList 和 LinkedList。这两个家伙在 Java 集合圈混迹多年,一个是看似无害的“数组党”,另一个则是自诩灵活的“链表帮”。大多数人可能随手 new 个 ArrayList 就开工了,LinkedList 只有在用队列或者 LRU 缓存那点场合才会想到。但你有没有认真琢磨过:为啥有两个 List 实现?底层到底区别在哪儿?我的选择会不会埋下什么性能地雷?
下面就来听听我的“踩坑血泪记”吧!😅
酒桌开局:谁快,谁慢?
说实话,刚学集合那会儿我完全不在意底层原理。谁让 List 方法名都一样!结果一次搞面试手撕代码,遇到了加班批量 add(),妥妥地催生了一场ArrayList vs LinkedList的惨烈大战。
我们先来聊聊:
- ArrayList 本质其实就是个会自动扩容的 Object 数组。用下标随便拿,特别带感;
- LinkedList 是典型的双向链表,增删元素砍瓜切菜,随地插拔不眨眼。
你以为这样就完事了?No, 朋友,细节才是魔鬼。
踩坑瞬间
轮到重头戏了!
那一次,我手里有几万个对象要批量插入和删除,而且操作位置还没那么规律(有头有尾还有中间)。一开始我自信满满地选择了 LinkedList,心说“插入/删除这不是链表的地盘嘛!”
结果数据一多,发现程序……卡得像在跑 Windows 98。抓起 JProfiler 一看,get(index) 成了大头。仔细想,哎呀,链表随机访问可是要一层层 next 找过去的啊。这一下醒悟:
LinkedList 的
get(int index)是 O(n) 复杂度,ArrayList 可是 O(1)!
下面献上一段让我梦回“Java 黑历史”的经典踩坑代码片段:
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i); // LinkedList 这里惨烈 O(n)
// ...
}
再别说你还在链表里写各种 for 循环遍历了,简直是“CPU 杀手”!
顺便插句话,ArrayList 每次 add 超了容量,都会“扩容”,核心逻辑其实就是下边这样:
// ArrayList 扩容精粹
Object[] newArray = new Object[oldArray.length * 1.5];
// System.arraycopy(oldArray, 0, newArray, 0, oldArray.length);
// ...
平时不用想,但插入很多大量数据时就感觉好像钱包被偷偷割了一刀:卡。
洞察&脑洞时间
知道真相的我,开始总结自己踩过哪些经典坑:
| 场景 | ArrayList | LinkedList |
|---|---|---|
| 随机访问 | 快速O(1) | 龟速O(n) |
| 尾部插入 | 超快,偶尔需扩容 | 不慢 |
| 中间插入/删除 | 低效(大量元素搬家) | 优势(只改指针) |
| 作为队列/双端队列 | 一般(实现麻烦) | 直接支持 |
所以别再迷迷糊糊“谁都用 ArrayList”了,根据业务场景选工具才是正道!
经验启示
每次被“无脑用 ArrayList”坑后,回头看其实很好笑。简单总结:
- 大部分场景都直接选 ArrayList,真需要链表特性的(例如大量头部插入、双端操作,或者需要 Deque 方法),才考虑 LinkedList;
- 遍历/查找为主的用 ArrayList,别拿 LinkedList 做大量 get(index) 了;
- 链表不是全能的,能不用就别用,尤其在多线程/缓存敏感场景。
最后再丢一个敲门砖:如果需求是“增删改查全家桶”,确定好你的主要瓶颈在哪。能用 ArrayList 绝不造轮子,不过偶尔也要考虑一下更有趣的新 List,比如 CopyOnWriteArrayList、或者干脆动用 Guava 的各种集合。
讲真,这俩类就像是老街区的两家早餐铺,想吃包子还是油条?务必下嘴前想明白自己的胃!
下次聊点更劲爆的集合骚操作~
收藏+关注,帮你远离无聊的踩坑!👻
共同学习,写下你的评论
评论加载中...
作者其他优质文章