Java集合类
Java 集合类是用于存储和操作多个对象的容器,位于 java.util 包下,主要分为 Collection 和 Map 两大体系,提供了丰富的数据结构和操作方法。以下是核心内容整理:
一、集合体系概览
- Collection:存储单个元素的集合,主要子接口包括
List(有序可重复)、Set(无序不可重复)、Queue(队列,FIFO)。 - Map:存储键值对(Key-Value)的集合,键唯一,值可重复。
二、Collection 接口核心实现类
1. List 接口(有序、可重复)
ArrayList
- 底层基于动态数组实现,查询快(索引访问),增删慢(需移动元素)。
- 初始容量 10,扩容时默认增长 50%(JDK 1.8+)。
- 线程不安全,效率高。
import java.util.ArrayList;
import java.util.List;
public class ArrayListDemo {
public static void main(String[] args) {
// 创建ArrayList(默认存10个元素,满了自动扩容)
List<String> fruits = new ArrayList<>();
// 添加元素
fruits.add("苹果");
fruits.add("香蕉");
fruits.add("苹果"); // 允许重复
// 按索引获取元素(查询快)
System.out.println(fruits.get(0)); // 输出:苹果
// 遍历元素
for (String fruit : fruits) {
System.out.println(fruit); // 顺序:苹果、香蕉、苹果
}
// 删除元素(会挪动后续元素,效率低)
fruits.remove(1); // 删除索引1的"香蕉"
}
}
LinkedList
- 底层基于双向链表实现,增删快(修改指针),查询慢(需遍历)。
- 实现了
Deque接口,可作为队列 / 栈使用。 - 线程不安全。
import java.util.LinkedList;
import java.util.List;
public class LinkedListDemo {
public static void main(String[] args) {
// 创建LinkedList
List<Integer> numbers = new LinkedList<>();
// 添加元素(增删快)
numbers.add(10);
numbers.add(20);
numbers.addFirst(5); // 头部添加
numbers.addLast(30); // 尾部添加
// 遍历
for (int num : numbers) {
System.out.println(num); // 输出:5、10、20、30
}
// 作为栈使用(先进后出)
LinkedList<String> stack = new LinkedList<>();
stack.push("A"); // 入栈
stack.push("B");
System.out.println(stack.pop()); // 出栈:B
}
}
Vector
- 与
ArrayList类似,但线程安全(方法加synchronized),效率低,已被弃用(推荐用Collections.synchronizedList替代)。
import java.util.Vector;
import java.util.Enumeration;
public class VectorDemo {
public static void main(String[] args) {
// 创建Vector(初始容量10,扩容默认翻倍,线程安全)
Vector<String> vector = new Vector<>();
// 添加元素(add方法线程安全,带synchronized修饰)
vector.add("元素1");
vector.add("元素2");
vector.add("元素3");
// 指定索引添加
vector.add(1, "插入的元素");
// 获取元素(按索引访问,类似ArrayList)
System.out.println("索引0的元素:" + vector.get(0)); // 输出:元素1
// 遍历方式1:普通for循环
System.out.println("\n普通for循环遍历:");
for (int i = 0; i < vector.size(); i++) {
System.out.println(vector.get(i));
}
// 遍历方式2:迭代器(Enumeration,Vector特有的遍历器)
System.out.println("\nEnumeration遍历:");
Enumeration<String> elements = vector.elements();
while (elements.hasMoreElements()) {
System.out.println(elements.nextElement());
}
// 修改元素
vector.set(0, "修改后的元素1");
System.out.println("\n修改后索引0的元素:" + vector.get(0));
// 删除元素
vector.remove(2); // 删除索引2的元素
System.out.println("\n删除后元素数量:" + vector.size());
// 判断是否包含某个元素
System.out.println("是否包含'元素2':" + vector.contains("元素2"));
}
}
2. Set 接口(无序、不可重复,基于 equals() 和 hashCode() 判断)
HashSet
- 底层基于哈希表(HashMap)实现,存储无序,查询 / 增删效率高(O (1))。
- 元素需重写
hashCode()和equals()保证唯一性。
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
// 创建HashSet(自动去重)
Set<String> names = new HashSet<>();
names.add("张三");
names.add("李四");
names.add("张三"); // 重复元素,不会被存入
// 遍历(无序)
for (String name : names) {
System.out.println(name); // 可能输出:李四、张三(顺序不确定)
}
}
}
LinkedHashSet
- 继承
HashSet,底层多了双向链表记录插入顺序,兼具哈希表的高效和顺序性。
import java.util.LinkedHashSet;
import java.util.Set;
public class LinkedHashSetDemo {
public static void main(String[] args) {
// 创建LinkedHashSet(去重 + 保留插入顺序)
Set<String> books = new LinkedHashSet<>();
// 添加元素
books.add("Java编程思想");
books.add("深入理解Java虚拟机");
books.add("Java并发编程实战");
books.add("Java编程思想"); // 重复元素,不会被存入
// 遍历集合(按插入顺序输出,与HashSet的无序不同)
System.out.println("LinkedHashSet遍历(插入顺序):");
for (String book : books) {
System.out.println(book);
}
// 输出顺序:
// Java编程思想
// 深入理解Java虚拟机
// Java并发编程实战
// 常用方法演示
System.out.println("\n是否包含《深入理解Java虚拟机》:" + books.contains("深入理解Java虚拟机")); // true
System.out.println("集合大小:" + books.size()); // 3
// 删除元素
books.remove("Java并发编程实战");
System.out.println("\n删除后剩余元素:");
for (String book : books) {
System.out.println(book);
}
// 输出:
// Java编程思想
// 深入理解Java虚拟机
}
}
TreeSet
- 底层基于红黑树实现,元素自动排序(自然排序或自定义
Comparator)。 - 查询 / 增删效率 O (log n),需元素可比较(实现
Comparable接口)。
import java.util.TreeSet;
import java.util.Set;
public class TreeSetDemo {
public static void main(String[] args) {
// 创建TreeSet(自动按自然顺序排序)
Set<Integer> nums = new TreeSet<>();
nums.add(30);
nums.add(10);
nums.add(20);
// 遍历(已排序)
for (int num : nums) {
System.out.println(num); // 输出:10、20、30
}
}
}
3. Queue 接口(队列,先进先出)
ArrayDeque
- 基于动态数组的双端队列,效率高于
LinkedList,可作为栈(push/pop)使用。
import java.util.ArrayDeque;
import java.util.Queue;
public class ArrayDequeDemo {
public static void main(String[] args) {
// 作为队列(先进先出)
Queue<String> queue = new ArrayDeque<>();
queue.offer("第一个人"); // 入队
queue.offer("第二个人");
System.out.println(queue.poll()); // 出队:第一个人
// 作为栈(先进后出)
ArrayDeque<String> stack = new ArrayDeque<>();
stack.push("A");
stack.push("B");
System.out.println(stack.pop()); // 出栈:B
}
}
PriorityQueue
- 优先级队列,元素按优先级排序(默认小顶堆),需元素可比较。
import java.util.PriorityQueue;
import java.util.Queue;
public class PriorityQueueDemo {
public static void main(String[] args) {
// 创建PriorityQueue(默认按自然顺序排序,小顶堆:每次取出最小元素)
Queue<Integer> pq = new PriorityQueue<>();
// 添加元素
pq.offer(30);
pq.offer(10);
pq.offer(20);
pq.offer(5);
// 优先级队列的特点:取出元素时按优先级(从小到大)
System.out.println("按优先级取出元素:");
while (!pq.isEmpty()) {
System.out.println(pq.poll()); // 每次取出最小的元素
}
// 输出顺序:5 → 10 → 20 → 30
}
}
三、Map 接口核心实现类(键值对存储)
HashMap(JDK 1.8+)
- 底层:数组 + 链表(当链表长度 > 8 时转为红黑树,< 6 时退化为链表)。
- 特点:键无序,允许键为
null(仅一个),值可null;线程不安全,效率高。 - 初始容量 16,负载因子 0.75,扩容时容量翻倍。
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class HashMapDemo {
public static void main(String[] args) {
// 创建HashMap(键值对,键唯一)
Map<String, Integer> scoreMap = new HashMap<>();
// 添加键值对
scoreMap.put("张三", 90);
scoreMap.put("李四", 85);
scoreMap.put("张三", 95); // 键重复,会覆盖值
// 获取值
System.out.println(scoreMap.get("张三")); // 输出:95
// 方式1:遍历键值对效率最高,是最常用的方式。
for (Map.Entry<String, Integer> entry : scoreMap.entrySet()) {
System.out.println(entry.getKey() + ":" + entry.getValue());
}
// 方式2:遍历所有键 通过keySet()获取所有键,再通过键获取值,适合只需操作键或单独获取值的场景。
Iterator<String> iterator = scoreMap.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
System.out.println( key + ":" + scoreMap.get(key));
}
// 方式3:遍历值,适合只需要值、无需键的场景
for (Integer value : scoreMap.values()) {
System.out.println(value);
}
// 方式4:forEach 流式遍历(最简洁),JDK 8 及以上推荐使用。
scoreMap.forEach((key, value) -> {
System.out.println( key + ":" + value);
});
}
}
LinkedHashMap
- 继承
HashMap,底层多了双向链表记录键值对插入顺序或访问顺序(可用于 LRU 缓存)。
import java.util.LinkedHashMap;
import java.util.Map;
public class LinkedHashMapDemo {
public static void main(String[] args) {
// 创建LinkedHashMap(默认按插入顺序存储)
Map<String, String> map = new LinkedHashMap<>();
// 添加键值对
map.put("name", "张三");
map.put("age", "20");
map.put("gender", "男");
map.put("score", "90");
// 遍历(按插入顺序输出,与HashMap的无序不同)
System.out.println("按插入顺序遍历:");
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey() + " → " + entry.getValue());
}
// 输出顺序:
// name → 张三
// age → 20
// gender → 男
// score → 90
}
}
TreeMap
- 底层基于红黑树,键自动排序(自然排序或自定义
Comparator),键不可为null。
import java.util.TreeMap;
import java.util.Map;
public class TreeMapDemo {
public static void main(String[] args) {
// 创建TreeMap(自动按键排序)
Map<String, String> dict = new TreeMap<>();
dict.put("banana", "香蕉");
dict.put("apple", "苹果");
dict.put("cat", "猫");
// 遍历(按键的字母顺序排序)
for (Map.Entry<String, String> entry : dict.entrySet()) {
System.out.println(entry.getKey() + "→" + entry.getValue());
// 输出:apple→苹果、banana→香蕉、cat→猫
}
}
}
Hashtable
- 古老实现,线程安全(方法加
synchronized),效率低,键和值都不可为null,已被ConcurrentHashMap替代。
ConcurrentHashMap
- 线程安全的哈希表,JDK 1.8 采用 CAS + 同步锁(分段锁优化为节点锁),效率高于
Hashtable。
import java.util.concurrent.ConcurrentHashMap;
import java.util.Map;
public class ConcurrentHashMapDemo {
// 共享的ConcurrentHashMap
private static final Map<Integer, Integer> concurrentMap = new ConcurrentHashMap<>();
public static void main(String[] args) throws InterruptedException {
// 线程1:添加元素
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
concurrentMap.put(i, i); // 并发添加,无需额外同步
}
});
// 线程2:读取并修改元素
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 1000; i++) {
// 并发读取和修改,安全无异常
concurrentMap.computeIfPresent(i, (k, v) -> v * 2); // 存在则翻倍
}
});
// 启动线程
thread1.start();
thread2.start();
// 等待线程结束
thread1.join();
thread2.join();
// 验证结果(总数应为1000,且值正确)
System.out.println("最终元素数量:" + concurrentMap.size()); // 1000
System.out.println("键999的值:" + concurrentMap.get(999)); // 1998(999*2)
}
}
四、集合工具类(java.util.Collections)
提供静态方法操作集合,如:
- 排序:
sort(list)、sort(list, comparator) - 线程安全包装:
synchronizedList(list)、synchronizedMap(map) - 不可变集合:
unmodifiableList(list)、emptyList() - 查找:
binarySearch(list, key)(二分查找,需先排序)
五、选择建议
- 查询多、增删少:
ArrayList - 增删多、查询少:
LinkedList - 去重且无序:
HashSet - 去重且排序:
TreeSet - 键值对且无序:
HashMap - 键值对且排序:
TreeMap - 线程安全:
ConcurrentHashMap(Map)、CopyOnWriteArrayList(List)
六、注意事项
- 集合存储的是对象引用,基本类型需用包装类(如
Integer、Boolean)。 HashSet/HashMap的元素需正确重写hashCode()和equals(),否则可能导致重复元素。- 迭代器(
Iterator)遍历集合时,若中途修改集合(如add/remove),会抛出ConcurrentModificationException(快速失败机制)。
掌握这些核心类的特性和适用场景,能高效处理 Java 中的数据存储与操作需求。