Java 集合框架核心知识手册
1. 集合框架体系核心区别
1.1 List 接口(有序、可重复)
ArrayList
底层:动态数组(
Object[]),默认初始容量 10
性能:
随机访问(
get(index)):O(1)(直接通过索引定位)中间增删(
add(index,e)/remove(index)):O(n)(需移动元素)
场景:频繁查询、尾端增删(如用户列表展示)
LinkedList
底层:双向链表(节点含
prev/next指针),实现Deque接口
性能:
随机访问:O(n)(需遍历链表)
中间增删:O(1)(仅改指针,定位节点后)
场景:频繁中间增删、队列 / 栈操作(如消息队列)
1.2 Set 接口(无序 / 有序、不可重复)
HashSet
底层:基于HashMap(元素存key,value为固定空对象)
核心:
去重:依赖
hashCode()+equals()(需同时重写)
性能:查找 / 增删平均O(1),支持 1 个null
场景:快速去重、无需排序(如过滤重复标签)
TreeSet
底层:基于TreeMap(红黑树结构)
核心:
去重排序:依赖
Comparable(自然排序)或Comparator(自定义排序)
性能:查找 / 增删O(log n),不支持null
场景:去重 + 排序(如成绩排行榜)
1.3 Map 接口(键值对、key 不可重复)
HashMap
底层:数组 + 链表 / 红黑树(JDK8+),默认容量 16,负载因子 0.75
性能:查找 / 增删平均O(1),支持 1 个null键,key无序
场景:快速键值查询(如缓存用户信息)
TreeMap
底层:红黑树
核心:
key有序:支持自然排序 / 自定义排序
功能:支持范围查询(
subMap())、首尾key获取
场景:键值排序 + 范围查询(如日期 - 数据映射)
1.4 三大接口对比表
2. 集合选型场景分析
3. 实操任务实现
3.1 手写 ArrayList 扩容逻辑(模拟 grow () 方法)
import java.util.Arrays;
public class CustomArrayList {
private Object[] elementData; // 存储数组
private int size; // 元素数量
private static final int DEFAULT_CAPACITY = 10; // 默认容量
// 无参构造
public CustomArrayList() {
this.elementData = new Object[DEFAULT_CAPACITY];
}
// 扩容核心方法
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
// 新容量 = 旧容量的1.5倍(位运算:oldCapacity >> 1 = 旧容量/2)
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 若新容量仍不足,用最小需求容量
if (newCapacity < minCapacity) {
newCapacity = minCapacity;
}
// 数组拷贝(核心步骤)
elementData = Arrays.copyOf(elementData, newCapacity);
System.out.println("扩容:" + oldCapacity + "→" + newCapacity);
}
// 添加元素(触发扩容)
public void add(Object e) {
if (size >= elementData.length) {
grow(size + 1); // 至少需要size+1的容量
}
elementData[size++] = e;
}
// 测试
public static void main(String[] args) {
CustomArrayList list = new CustomArrayList();
for (int i = 0; i < 15; i++) { // 超过默认容量10,触发扩容
list.add("元素" + i);
}
}
}3.2 ArrayList 与 LinkedList 性能对比测试
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class PerformanceTest {
private static final int LOOP = 10000; // 测试次数
public static void main(String[] args) {
List<Integer> arrayList = new ArrayList<>();
List<Integer> linkedList = new LinkedList<>();
// 1. 中间添加性能
long arrayAddTime = testAddMiddle(arrayList);
long linkedAddTime = testAddMiddle(linkedList);
System.out.println("中间添加耗时:ArrayList=" + arrayAddTime + "ms,LinkedList=" + linkedAddTime + "ms");
// 2. 随机访问性能
fillData(arrayList);
fillData(linkedList);
long arrayGetTime = testGet(arrayList);
long linkedGetTime = testGet(linkedList);
System.out.println("随机访问耗时:ArrayList=" + arrayGetTime + "ms,LinkedList=" + linkedGetTime + "ms");
}
// 中间位置添加
private static long testAddMiddle(List<Integer> list) {
long start = System.currentTimeMillis();
for (int i = 0; i < LOOP; i++) {
list.add(list.size() / 2, i);
}
return System.currentTimeMillis() - start;
}
// 随机访问
private static long testGet(List<Integer> list) {
long start = System.currentTimeMillis();
for (int i = 0; i < LOOP; i++) {
list.get(i % list.size());
}
return System.currentTimeMillis() - start;
}
// 填充测试数据
private static void fillData(List<Integer> list) {
list.clear();
for (int i = 0; i < LOOP; i++) {
list.add(i);
}
}
}测试结果说明:
中间添加:LinkedList 耗时远低于 ArrayList(无需移动元素)
随机访问:ArrayList 耗时远低于 LinkedList(直接索引定位)
4. 集合选型速查表
备注:
所有集合均线程不安全,多线程场景需用
Collections.synchronizedXXX()或ConcurrentHashMap
自定义对象作
HashSet/HashMap的元素 /key 时,必须重写hashCode()和equals()