深入理解 Java 集合框架
目录
1. 集合框架概述
1.1 什么是集合框架?
1.2 集合框架的体系结构
2. Collection 接口及其实现
2.1 List 接口
ArrayList
LinkedList
Vector vs ArrayList
2.2 Set 接口
HashSet
LinkedHashSet
TreeSet
2.3 Queue 接口
PriorityQueue
ArrayDeque
3. Map 接口及其实现
3.1 HashMap
3.2 LinkedHashMap
3.3 TreeMap
3.4 Hashtable vs HashMap
4. 集合的线程安全版本
4.1 同步包装器
4.2 Concurrent 集合(Java 5+)
5. 集合的性能比较
5.1 List 性能比较
5.2 Set 性能比较
5.3 Map 性能比较
6. 集合的最佳实践
6.1 选择合适的集合
6.2 初始化容量
6.3 使用增强for循环和迭代器
6.4 Java 8+ 新特性
7. 常见面试问题
7.1 HashMap 的工作原理
7.2 ArrayList 和 LinkedList 的区别
7.3 ConcurrentHashMap 的实现原理
8. 总结
关键要点:
选择指南:
Java 集合框架(Java Collections Framework)是 Java 语言中最重要的组成部分之一。
1. 集合框架概述
1.1 什么是集合框架?
Java 集合框架是一组用于表示和操作集合的统一架构,包含:
- 接口:定义集合的基本操作
- 实现:接口的具体实现类
- 算法:对集合进行操作的方法(如排序、搜索)
1.2 集合框架的体系结构
Collection├── List (有序、可重复)│ ├── ArrayList│ ├── LinkedList│ └── Vector│ └── Stack│├── Set (无序、不可重复)│ ├── HashSet│ │ └── LinkedHashSet│ ├── TreeSet│ └── EnumSet│└── Queue (队列)├── PriorityQueue├── ArrayDeque└── LinkedListMap (键值对)├── HashMap│ └── LinkedHashMap├── TreeMap├── Hashtable│ └── Properties└── EnumMap
2. Collection 接口及其实现
2.1 List 接口
ArrayList
// ArrayList 示例
List<String> arrayList = new ArrayList<>();
arrayList.add("Java");
arrayList.add("Python");
arrayList.add("C++");// 随机访问高效
System.out.println(arrayList.get(1)); // 输出: Python// 遍历
for (String language : arrayList) {System.out.println(language);
}// 特点:基于数组,随机访问快,插入删除慢(需要移动元素)
LinkedList
// LinkedList 示例
List<String> linkedList = new LinkedList<>();
linkedList.add("Apple");
linkedList.add("Banana");
linkedList.addFirst("Orange"); // 在开头添加// 插入删除高效
linkedList.remove(1); // 删除第二个元素// 特点:基于双向链表,插入删除快,随机访问慢
Vector vs ArrayList
// Vector 是线程安全的,但性能较差
Vector<String> vector = new Vector<>();
vector.add("item1");
vector.add("item2");// ArrayList 非线程安全,但性能更好
List<String> arrayList = new ArrayList<>();
2.2 Set 接口
HashSet
// HashSet 示例
Set<String> hashSet = new HashSet<>();
hashSet.add("北京");
hashSet.add("上海");
hashSet.add("北京"); // 重复元素不会被添加System.out.println(hashSet); // 输出: [北京, 上海]
System.out.println(hashSet.contains("上海")); // true// 特点:基于HashMap,无序,查询速度快
LinkedHashSet
// LinkedHashSet 保持插入顺序
Set<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("第一");
linkedHashSet.add("第二");
linkedHashSet.add("第三");System.out.println(linkedHashSet); // 输出: [第一, 第二, 第三]
TreeSet
// TreeSet 自然排序
Set<String> treeSet = new TreeSet<>();
treeSet.add("orange");
treeSet.add("apple");
treeSet.add("banana");System.out.println(treeSet); // 输出: [apple, banana, orange]// 自定义排序
Set<Integer> customSet = new TreeSet<>(Comparator.reverseOrder());
customSet.add(5);
customSet.add(1);
customSet.add(10);System.out.println(customSet); // 输出: [10, 5, 1]
2.3 Queue 接口
PriorityQueue
// 优先级队列
Queue<Integer> priorityQueue = new PriorityQueue<>();
priorityQueue.offer(5);
priorityQueue.offer(1);
priorityQueue.offer(10);while (!priorityQueue.isEmpty()) {System.out.println(priorityQueue.poll()); // 输出: 1, 5, 10
}
ArrayDeque
// 双端队列
Deque<String> deque = new ArrayDeque<>();
deque.offerFirst("first");
deque.offerLast("last");
deque.offer("middle");System.out.println(deque.pollFirst()); // 输出: first
System.out.println(deque.pollLast()); // 输出: last
3. Map 接口及其实现
3.1 HashMap
// HashMap 示例
Map<String, Integer> hashMap = new HashMap<>();
hashMap.put("Alice", 25);
hashMap.put("Bob", 30);
hashMap.put("Charlie", 28);// 获取值
System.out.println(hashMap.get("Alice")); // 输出: 25// 遍历
for (Map.Entry<String, Integer> entry : hashMap.entrySet()) {System.out.println(entry.getKey() + ": " + entry.getValue());
}// Java 8+ 方法
hashMap.forEach((k, v) -> System.out.println(k + ": " + v));
3.2 LinkedHashMap
// 保持插入顺序的Map
Map<String, Integer> linkedHashMap = new LinkedHashMap<>();
linkedHashMap.put("z", 1);
linkedHashMap.put("a", 2);
linkedHashMap.put("b", 3);System.out.println(linkedHashMap.keySet()); // 输出: [z, a, b]
3.3 TreeMap
// 排序的Map
Map<String, Integer> treeMap = new TreeMap<>();
treeMap.put("orange", 1);
treeMap.put("apple", 2);
treeMap.put("banana", 3);System.out.println(treeMap.keySet()); // 输出: [apple, banana, orange]
3.4 Hashtable vs HashMap
// Hashtable 是线程安全的
Map<String, String> hashtable = new Hashtable<>();
hashtable.put("key", "value");// HashMap 非线程安全,但性能更好
Map<String, String> hashMap = new HashMap<>();
4. 集合的线程安全版本
4.1 同步包装器
// 创建线程安全的集合
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
Map<String, String> syncMap = Collections.synchronizedMap(new HashMap<>());
4.2 Concurrent 集合(Java 5+)
// 并发集合,性能更好
ConcurrentHashMap<String, Integer> concurrentMap = new ConcurrentHashMap<>();
CopyOnWriteArrayList<String> copyOnWriteList = new CopyOnWriteArrayList<>();
ConcurrentLinkedQueue<String> concurrentQueue = new ConcurrentLinkedQueue<>();
5. 集合的性能比较
5.1 List 性能比较
| 操作 | ArrayList | LinkedList |
| 随机访问 | O(1) | O(n) |
| 头部插入 | O(n) | O(1) |
| 尾部插入 | O(1) | O(1) |
| 中间插入 | O(n) | O(n) |
| 删除 | O(n) | O(1) |
5.2 Set 性能比较
| 操作 | HashSet | TreeSet | LinkedHashSet |
| 添加 | O(1) | O(log n) | O(1) |
| 包含 | O(1) | O(log n) | O(1) |
| 删除 | O(1) | O(log n) | O(1) |
| 有序 | 否 | 是 | 插入顺序 |
5.3 Map 性能比较
| 操作 | HashMap | TreeMap | LinkedHashMap |
| 添加 | O(1) | O(log n) | O(1) |
| 获取 | O(1) | O(log n) | O(1) |
| 删除 | O(1) | O(log n) | O(1) |
| 有序 | 否 | 是 | 插入顺序 |
6. 集合的最佳实践
6.1 选择合适的集合
// 根据需求选择集合类型
if (需要快速随机访问) {return new ArrayList<>();
} else if (需要频繁插入删除) {return new LinkedList<>();
} else if (需要去重) {return new HashSet<>();
} else if (需要键值对) {return new HashMap<>();
} else if (需要排序) {return new TreeSet<>(); // 或 TreeMap
}
6.2 初始化容量
// 预估大小,避免扩容开销
List<String> list = new ArrayList<>(1000);
Map<String, Integer> map = new HashMap<>(1024, 0.75f);
6.3 使用增强for循环和迭代器
// 推荐写法
for (String item : collection) {System.out.println(item);
}// 需要删除时使用迭代器
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {String item = iterator.next();if (shouldRemove(item)) {iterator.remove(); // 安全的删除方式}
}
6.4 Java 8+ 新特性
// Stream API
List<String> filtered = list.stream().filter(s -> s.startsWith("A")).map(String::toUpperCase).collect(Collectors.toList());// computeIfAbsent
Map<String, List<String>> map = new HashMap<>();
map.computeIfAbsent("key", k -> new ArrayList<>()).add("value");
7. 常见面试问题
7.1 HashMap 的工作原理
HashMap 基于数组+链表/红黑树实现,通过 hashCode() 计算存储位置,使用 equals() 解决哈希冲突。
7.2 ArrayList 和 LinkedList 的区别
- ArrayList 基于数组,随机访问快
- LinkedList 基于链表,插入删除快
7.3 ConcurrentHashMap 的实现原理
使用分段锁(Java 7)或 CAS + synchronized(Java 8),提高并发性能。
8. 总结
Java 集合框架提供了丰富的数据结构和算法,理解它们的特性和适用场景对于编写高效代码至关重要:
关键要点:
- 根据需求选择集合:考虑性能、线程安全、排序需求
- 理解底层实现:知道不同集合的时间复杂度
- 注意线程安全:多线程环境使用并发集合或同步包装器
- 利用新特性:Java 8+ 的 Stream API 和 Lambda 表达式
选择使用:
- List:需要有序、可重复的元素
- Set:需要去重、快速查找
- Map:需要键值对存储
- Queue:需要队列操作
