Java集合框架(Collections Framework)是Java编程中最重要的特性之一,它提供了一套设计良好的接口和类来存储和操作对象集合。本章将详细介绍各种集合类型及其使用方法。
7.1 集合框架概述
7.1.1 集合框架结构
import java.util.*;
/**
* 集合框架概述演示
*/
public class CollectionsOverview {
public static void main(String[] args) {
System.out.println("=== Java集合框架概述 ===");
demonstrateCollectionHierarchy();
demonstrateBasicOperations();
}
public static void demonstrateCollectionHierarchy() {
System.out.println("\n=== 集合框架层次结构 ===");
System.out.println("");
System.out.println("Collection接口层次结构:");
System.out.println("Collection (接口)");
System.out.println("├── List (接口) - 有序、可重复");
System.out.println("│ ├── ArrayList - 动态数组实现");
System.out.println("│ ├── LinkedList - 双向链表实现");
System.out.println("│ └── Vector - 同步的动态数组");
System.out.println("├── Set (接口) - 无序、不可重复");
System.out.println("│ ├── HashSet - 哈希表实现");
System.out.println("│ ├── LinkedHashSet - 保持插入顺序的HashSet");
System.out.println("│ └── TreeSet - 红黑树实现,自动排序");
System.out.println("└── Queue (接口) - 队列");
System.out.println(" ├── PriorityQueue - 优先队列");
System.out.println(" └── Deque (接口) - 双端队列");
System.out.println(" └── ArrayDeque - 数组实现的双端队列");
System.out.println("");
System.out.println("Map接口层次结构:");
System.out.println("Map (接口) - 键值对映射");
System.out.println("├── HashMap - 哈希表实现");
System.out.println("├── LinkedHashMap - 保持插入顺序的HashMap");
System.out.println("├── TreeMap - 红黑树实现,按键排序");
System.out.println("└── Hashtable - 同步的哈希表");
}
public static void demonstrateBasicOperations() {
System.out.println("\n=== 集合基本操作演示 ===");
// Collection接口的基本方法
Collection<String> collection = new ArrayList<>();
System.out.println("\n1. 添加元素:");
collection.add("Apple");
collection.add("Banana");
collection.add("Cherry");
System.out.println("集合内容: " + collection);
System.out.println("集合大小: " + collection.size());
System.out.println("\n2. 查询操作:");
System.out.println("是否包含Apple: " + collection.contains("Apple"));
System.out.println("是否包含Orange: " + collection.contains("Orange"));
System.out.println("集合是否为空: " + collection.isEmpty());
System.out.println("\n3. 删除操作:");
collection.remove("Banana");
System.out.println("删除Banana后: " + collection);
System.out.println("\n4. 批量操作:");
Collection<String> otherCollection = Arrays.asList("Date", "Elderberry");
collection.addAll(otherCollection);
System.out.println("添加其他集合后: " + collection);
System.out.println("\n5. 遍历操作:");
System.out.print("使用增强for循环: ");
for (String item : collection) {
System.out.print(item + " ");
}
System.out.println();
System.out.print("使用Iterator: ");
Iterator<String> iterator = collection.iterator();
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
System.out.println();
System.out.print("使用Stream API: ");
collection.stream().forEach(item -> System.out.print(item + " "));
System.out.println();
System.out.println("\n6. 转换为数组:");
String[] array = collection.toArray(new String[0]);
System.out.println("转换为数组: " + Arrays.toString(array));
System.out.println("\n7. 清空集合:");
collection.clear();
System.out.println("清空后集合大小: " + collection.size());
}
}
7.1.2 泛型在集合中的应用
import java.util.*;
/**
* 泛型在集合中的应用演示
*/
public class GenericsInCollections {
public static void main(String[] args) {
System.out.println("=== 泛型在集合中的应用 ===");
demonstrateBasicGenerics();
demonstrateWildcards();
demonstrateBoundedGenerics();
}
public static void demonstrateBasicGenerics() {
System.out.println("\n--- 基本泛型使用 ---");
// ❌ 不使用泛型(不推荐)
List rawList = new ArrayList();
rawList.add("String");
rawList.add(123);
rawList.add(new Date());
// 需要强制类型转换,容易出错
for (Object obj : rawList) {
System.out.println("原始类型: " + obj + " (" + obj.getClass().getSimpleName() + ")");
}
// ✅ 使用泛型(推荐)
List<String> stringList = new ArrayList<>();
stringList.add("Apple");
stringList.add("Banana");
// stringList.add(123); // 编译错误,类型安全
// 不需要类型转换
for (String str : stringList) {
System.out.println("字符串: " + str.toUpperCase());
}
// 不同类型的泛型集合
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
System.out.println("整数列表: " + intList);
System.out.println("浮点数列表: " + doubleList);
}
public static void demonstrateWildcards() {
System.out.println("\n--- 通配符使用 ---");
List<Integer> intList = Arrays.asList(1, 2, 3, 4, 5);
List<Double> doubleList = Arrays.asList(1.1, 2.2, 3.3);
List<String> stringList = Arrays.asList("A", "B", "C");
// 1. 无界通配符 ?
printListSize(intList);
printListSize(doubleList);
printListSize(stringList);
// 2. 上界通配符 ? extends
System.out.println("数字列表求和:");
System.out.println("整数和: " + sumNumbers(intList));
System.out.println("浮点数和: " + sumNumbers(doubleList));
// 3. 下界通配符 ? super
List<Number> numberList = new ArrayList<>();
addNumbers(numberList);
System.out.println("添加数字后: " + numberList);
}
// 无界通配符:可以接受任何类型的List
public static void printListSize(List<?> list) {
System.out.println("列表大小: " + list.size() + ", 内容: " + list);
}
// 上界通配符:只能读取,不能添加(除了null)
public static double sumNumbers(List<? extends Number> numbers) {
double sum = 0.0;
for (Number num : numbers) {
sum += num.doubleValue();
}
return sum;
}
// 下界通配符:可以添加,但读取时只能当作Object
public static void addNumbers(List<? super Integer> list) {
list.add(10);
list.add(20);
list.add(30);
// Integer item = list.get(0); // 编译错误
Object item = list.get(0); // 只能当作Object读取
}
public static void demonstrateBoundedGenerics() {
System.out.println("\n--- 有界泛型 ---");
// 创建不同类型的容器
NumberContainer<Integer> intContainer = new NumberContainer<>(42);
NumberContainer<Double> doubleContainer = new NumberContainer<>(3.14);
System.out.println("整数容器: " + intContainer.getValue());
System.out.println("整数容器数值操作: " + intContainer.getDoubleValue());
System.out.println("浮点容器: " + doubleContainer.getValue());
System.out.println("浮点容器数值操作: " + doubleContainer.getDoubleValue());
// 比较容器
System.out.println("容器比较: " + intContainer.compareTo(doubleContainer));
}
// 有界泛型类:T必须是Number的子类
static class NumberContainer<T extends Number> implements Comparable<NumberContainer<? extends Number>> {
private T value;
public NumberContainer(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public double getDoubleValue() {
return value.doubleValue();
}
@Override
public int compareTo(NumberContainer<? extends Number> other) {
return Double.compare(this.getDoubleValue(), other.getDoubleValue());
}
@Override
public String toString() {
return "NumberContainer{value=" + value + "}";
}
}
}
7.2 List接口和实现类
7.2.1 ArrayList详解
import java.util.*;
import java.util.function.Predicate;
/**
* ArrayList详细演示
*/
public class ArrayListDemo {
public static void main(String[] args) {
System.out.println("=== ArrayList详细演示 ===");
demonstrateBasicOperations();
demonstrateAdvancedOperations();
demonstratePerformanceCharacteristics();
demonstrateCommonUseCases();
}
public static void demonstrateBasicOperations() {
System.out.println("\n--- ArrayList基本操作 ---");
// 1. 创建ArrayList
List<String> fruits = new ArrayList<>();
System.out.println("初始容量: " + fruits.size());
// 指定初始容量
List<String> vegetables = new ArrayList<>(20);
// 从其他集合创建
List<String> colors = new ArrayList<>(Arrays.asList("Red", "Green", "Blue"));
System.out.println("从数组创建: " + colors);
// 2. 添加元素
fruits.add("Apple");
fruits.add("Banana");
fruits.add("Cherry");
System.out.println("添加元素后: " + fruits);
// 在指定位置插入
fruits.add(1, "Apricot");
System.out.println("在索引1插入Apricot: " + fruits);
// 3. 访问元素
System.out.println("\n访问元素:");
System.out.println("第一个元素: " + fruits.get(0));
System.out.println("最后一个元素: " + fruits.get(fruits.size() - 1));
// 4. 修改元素
fruits.set(2, "Coconut");
System.out.println("修改索引2的元素: " + fruits);
// 5. 查找元素
System.out.println("\n查找元素:");
System.out.println("Apple的索引: " + fruits.indexOf("Apple"));
System.out.println("包含Banana: " + fruits.contains("Banana"));
// 6. 删除元素
fruits.remove("Apricot");
System.out.println("删除Apricot: " + fruits);
fruits.remove(0);
System.out.println("删除索引0的元素: " + fruits);
}
public static void demonstrateAdvancedOperations() {
System.out.println("\n--- ArrayList高级操作 ---");
List<Integer> numbers = new ArrayList<>(Arrays.asList(5, 2, 8, 1, 9, 3));
System.out.println("原始列表: " + numbers);
// 1. 排序
List<Integer> sortedNumbers = new ArrayList<>(numbers);
Collections.sort(sortedNumbers);
System.out.println("升序排序: " + sortedNumbers);
Collections.sort(sortedNumbers, Collections.reverseOrder());
System.out.println("降序排序: " + sortedNumbers);
// 2. 查找
Collections.sort(numbers); // 二分查找需要有序列表
int index = Collections.binarySearch(numbers, 5);
System.out.println("二分查找5的位置: " + index);
// 3. 最大值和最小值
System.out.println("最大值: " + Collections.max(numbers));
System.out.println("最小值: " + Collections.min(numbers));
// 4. 反转
Collections.reverse(numbers);
System.out.println("反转后: " + numbers);
// 5. 打乱
Collections.shuffle(numbers);
System.out.println("打乱后: " + numbers);
// 6. 子列表
List<Integer> subList = numbers.subList(1, 4);
System.out.println("子列表[1,4): " + subList);
// 7. 批量操作
List<Integer> evenNumbers = Arrays.asList(2, 4, 6, 8);
numbers.retainAll(evenNumbers); // 保留交集
System.out.println("保留偶数: " + numbers);
}
public static void demonstratePerformanceCharacteristics() {
System.out.println("\n--- ArrayList性能特征 ---");
List<Integer> list = new ArrayList<>();
// 1. 添加性能测试
long startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
list.add(i);
}
long endTime = System.nanoTime();
System.out.println("添加100000个元素耗时: " + (endTime - startTime) / 1000000 + "ms");
// 2. 随机访问性能
Random random = new Random();
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
int index = random.nextInt(list.size());
list.get(index);
}
endTime = System.nanoTime();
System.out.println("随机访问10000次耗时: " + (endTime - startTime) / 1000000 + "ms");
// 3. 中间插入性能(相对较慢)
startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
list.add(list.size() / 2, i);
}
endTime = System.nanoTime();
System.out.println("中间插入1000个元素耗时: " + (endTime - startTime) / 1000000 + "ms");
System.out.println("\nArrayList特点:");
System.out.println("- 基于动态数组实现");
System.out.println("- 随机访问速度快 O(1)");
System.out.println("- 尾部添加速度快 O(1)");
System.out.println("- 中间插入/删除较慢 O(n)");
System.out.println("- 非线程安全");
}
public static void demonstrateCommonUseCases() {
System.out.println("\n--- ArrayList常见用例 ---");
// 1. 学生成绩管理
List<Student> students = new ArrayList<>();
students.add(new Student("张三", 85));
students.add(new Student("李四", 92));
students.add(new Student("王五", 78));
students.add(new Student("赵六", 96));
System.out.println("\n学生列表:");
for (Student student : students) {
System.out.println(student);
}
// 按成绩排序
students.sort((s1, s2) -> Integer.compare(s2.getScore(), s1.getScore()));
System.out.println("\n按成绩降序排序:");
students.forEach(System.out::println);
// 筛选高分学生
List<Student> highScoreStudents = new ArrayList<>();
for (Student student : students) {
if (student.getScore() >= 90) {
highScoreStudents.add(student);
}
}
System.out.println("\n高分学生(>=90):");
highScoreStudents.forEach(System.out::println);
// 使用Stream API(更简洁)
System.out.println("\n使用Stream筛选高分学生:");
students.stream()
.filter(s -> s.getScore() >= 90)
.forEach(System.out::println);
// 2. 动态数据收集
List<String> userInputs = new ArrayList<>();
Scanner scanner = new Scanner("apple\nbanana\ncherry\nquit");
System.out.println("\n模拟用户输入收集:");
String input;
while (scanner.hasNext() && !(input = scanner.next()).equals("quit")) {
userInputs.add(input);
System.out.println("添加: " + input);
}
System.out.println("收集到的输入: " + userInputs);
// 3. 缓存和临时存储
List<String> cache = new ArrayList<>();
// 模拟缓存操作
addToCache(cache, "data1");
addToCache(cache, "data2");
addToCache(cache, "data3");
System.out.println("\n缓存内容: " + cache);
// 清理缓存
cache.removeIf(item -> item.startsWith("data1"));
System.out.println("清理后缓存: " + cache);
}
private static void addToCache(List<String> cache, String data) {
cache.add(data);
System.out.println("添加到缓存: " + data);
}
// 学生类
static class Student {
private String name;
private int score;
public Student(String name, int score) {
this.name = name;
this.score = score;
}
public String getName() {
return name;
}
public int getScore() {
return score;
}
@Override
public String toString() {
return String.format("Student{name='%s', score=%d}", name, score);
}
}
}
7.2.2 LinkedList详解
import java.util.*;
/**
* LinkedList详细演示
*/
public class LinkedListDemo {
public static void main(String[] args) {
System.out.println("=== LinkedList详细演示 ===");
demonstrateBasicOperations();
demonstrateDequeOperations();
demonstratePerformanceComparison();
demonstrateUseCases();
}
public static void demonstrateBasicOperations() {
System.out.println("\n--- LinkedList基本操作 ---");
// 1. 创建LinkedList
LinkedList<String> list = new LinkedList<>();
// 2. 添加元素
list.add("First");
list.add("Second");
list.add("Third");
System.out.println("基本添加: " + list);
// 3. 头部和尾部操作
list.addFirst("New First");
list.addLast("New Last");
System.out.println("头尾添加后: " + list);
// 4. 访问头部和尾部
System.out.println("\n访问操作:");
System.out.println("第一个元素: " + list.getFirst());
System.out.println("最后一个元素: " + list.getLast());
System.out.println("查看第一个元素: " + list.peekFirst());
System.out.println("查看最后一个元素: " + list.peekLast());
// 5. 删除操作
System.out.println("\n删除操作:");
String removedFirst = list.removeFirst();
String removedLast = list.removeLast();
System.out.println("删除的第一个元素: " + removedFirst);
System.out.println("删除的最后一个元素: " + removedLast);
System.out.println("删除后的列表: " + list);
// 6. 中间操作
list.add(1, "Inserted");
System.out.println("在索引1插入: " + list);
String element = list.get(1);
System.out.println("获取索引1的元素: " + element);
list.set(1, "Modified");
System.out.println("修改索引1的元素: " + list);
}
public static void demonstrateDequeOperations() {
System.out.println("\n--- LinkedList作为双端队列(Deque) ---");
Deque<Integer> deque = new LinkedList<>();
// 1. 队列操作 (FIFO)
System.out.println("\n队列操作 (FIFO):");
deque.offer(1); // 入队
deque.offer(2);
deque.offer(3);
System.out.println("入队后: " + deque);
while (!deque.isEmpty()) {
System.out.println("出队: " + deque.poll());
}
// 2. 栈操作 (LIFO)
System.out.println("\n栈操作 (LIFO):");
deque.push(1); // 入栈
deque.push(2);
deque.push(3);
System.out.println("入栈后: " + deque);
while (!deque.isEmpty()) {
System.out.println("出栈: " + deque.pop());
}
// 3. 双端操作
System.out.println("\n双端操作:");
deque.offerFirst(1);
deque.offerLast(2);
deque.offerFirst(0);
deque.offerLast(3);
System.out.println("双端添加后: " + deque);
System.out.println("从前端移除: " + deque.pollFirst());
System.out.println("从后端移除: " + deque.pollLast());
System.out.println("剩余元素: " + deque);
}
public static void demonstratePerformanceComparison() {
System.out.println("\n--- ArrayList vs LinkedList 性能比较 ---");
int size = 100000;
// 1. 顺序添加性能
System.out.println("\n1. 顺序添加性能测试:");
List<Integer> arrayList = new ArrayList<>();
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
arrayList.add(i);
}
long arrayListAddTime = System.nanoTime() - startTime;
List<Integer> linkedList = new LinkedList<>();
startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
linkedList.add(i);
}
long linkedListAddTime = System.nanoTime() - startTime;
System.out.println("ArrayList添加耗时: " + arrayListAddTime / 1000000 + "ms");
System.out.println("LinkedList添加耗时: " + linkedListAddTime / 1000000 + "ms");
// 2. 随机访问性能
System.out.println("\n2. 随机访问性能测试:");
Random random = new Random();
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
arrayList.get(random.nextInt(arrayList.size()));
}
long arrayListGetTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
linkedList.get(random.nextInt(linkedList.size()));
}
long linkedListGetTime = System.nanoTime() - startTime;
System.out.println("ArrayList随机访问耗时: " + arrayListGetTime / 1000000 + "ms");
System.out.println("LinkedList随机访问耗时: " + linkedListGetTime / 1000000 + "ms");
// 3. 头部插入性能
System.out.println("\n3. 头部插入性能测试:");
List<Integer> arrayListInsert = new ArrayList<>();
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
arrayListInsert.add(0, i);
}
long arrayListInsertTime = System.nanoTime() - startTime;
LinkedList<Integer> linkedListInsert = new LinkedList<>();
startTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
linkedListInsert.addFirst(i);
}
long linkedListInsertTime = System.nanoTime() - startTime;
System.out.println("ArrayList头部插入耗时: " + arrayListInsertTime / 1000000 + "ms");
System.out.println("LinkedList头部插入耗时: " + linkedListInsertTime / 1000000 + "ms");
System.out.println("\n性能总结:");
System.out.println("ArrayList: 随机访问快,中间插入慢");
System.out.println("LinkedList: 头尾操作快,随机访问慢");
}
public static void demonstrateUseCases() {
System.out.println("\n--- LinkedList适用场景 ---");
// 1. 实现LRU缓存
System.out.println("\n1. LRU缓存实现:");
LRUCache<String, String> cache = new LRUCache<>(3);
cache.put("key1", "value1");
cache.put("key2", "value2");
cache.put("key3", "value3");
System.out.println("添加3个元素: " + cache);
cache.get("key1"); // 访问key1,使其成为最近使用
cache.put("key4", "value4"); // 添加新元素,应该移除key2
System.out.println("访问key1后添加key4: " + cache);
// 2. 撤销/重做功能
System.out.println("\n2. 撤销/重做功能:");
UndoRedoManager<String> undoRedo = new UndoRedoManager<>();
undoRedo.execute("操作1");
undoRedo.execute("操作2");
undoRedo.execute("操作3");
System.out.println("执行3个操作后: " + undoRedo.getCurrentState());
undoRedo.undo();
System.out.println("撤销一次: " + undoRedo.getCurrentState());
undoRedo.redo();
System.out.println("重做一次: " + undoRedo.getCurrentState());
// 3. 音乐播放列表
System.out.println("\n3. 音乐播放列表:");
MusicPlaylist playlist = new MusicPlaylist();
playlist.addSong("Song 1");
playlist.addSong("Song 2");
playlist.addSong("Song 3");
System.out.println("当前播放: " + playlist.getCurrentSong());
System.out.println("下一首: " + playlist.nextSong());
System.out.println("上一首: " + playlist.previousSong());
playlist.shuffle();
System.out.println("随机播放后: " + playlist.getCurrentSong());
}
// 简单的LRU缓存实现
static class LRUCache<K, V> {
private final int capacity;
private final LinkedList<Node<K, V>> list;
private final Map<K, Node<K, V>> map;
public LRUCache(int capacity) {
this.capacity = capacity;
this.list = new LinkedList<>();
this.map = new HashMap<>();
}
public V get(K key) {
Node<K, V> node = map.get(key);
if (node == null) {
return null;
}
// 移动到头部
list.remove(node);
list.addFirst(node);
return node.value;
}
public void put(K key, V value) {
Node<K, V> existingNode = map.get(key);
if (existingNode != null) {
// 更新现有节点
existingNode.value = value;
list.remove(existingNode);
list.addFirst(existingNode);
} else {
// 添加新节点
Node<K, V> newNode = new Node<>(key, value);
if (list.size() >= capacity) {
// 移除最少使用的节点
Node<K, V> last = list.removeLast();
map.remove(last.key);
}
list.addFirst(newNode);
map.put(key, newNode);
}
}
@Override
public String toString() {
return list.toString();
}
static class Node<K, V> {
K key;
V value;
Node(K key, V value) {
this.key = key;
this.value = value;
}
@Override
public String toString() {
return key + "=" + value;
}
}
}
// 撤销/重做管理器
static class UndoRedoManager<T> {
private LinkedList<T> undoStack = new LinkedList<>();
private LinkedList<T> redoStack = new LinkedList<>();
private T currentState;
public void execute(T newState) {
if (currentState != null) {
undoStack.push(currentState);
}
currentState = newState;
redoStack.clear(); // 执行新操作后清空重做栈
}
public boolean undo() {
if (undoStack.isEmpty()) {
return false;
}
if (currentState != null) {
redoStack.push(currentState);
}
currentState = undoStack.pop();
return true;
}
public boolean redo() {
if (redoStack.isEmpty()) {
return false;
}
if (currentState != null) {
undoStack.push(currentState);
}
currentState = redoStack.pop();
return true;
}
public T getCurrentState() {
return currentState;
}
}
// 音乐播放列表
static class MusicPlaylist {
private LinkedList<String> songs = new LinkedList<>();
private int currentIndex = -1;
public void addSong(String song) {
songs.add(song);
if (currentIndex == -1) {
currentIndex = 0;
}
}
public String getCurrentSong() {
if (songs.isEmpty() || currentIndex < 0) {
return null;
}
return songs.get(currentIndex);
}
public String nextSong() {
if (songs.isEmpty()) {
return null;
}
currentIndex = (currentIndex + 1) % songs.size();
return getCurrentSong();
}
public String previousSong() {
if (songs.isEmpty()) {
return null;
}
currentIndex = (currentIndex - 1 + songs.size()) % songs.size();
return getCurrentSong();
}
public void shuffle() {
Collections.shuffle(songs);
currentIndex = 0;
}
}
}
7.2.3 Vector和ArrayList的比较
import java.util.*;
import java.util.concurrent.*;
/**
* Vector和ArrayList比较演示
*/
public class VectorVsArrayListDemo {
public static void main(String[] args) {
System.out.println("=== Vector vs ArrayList 比较 ===");
demonstrateBasicDifferences();
demonstrateThreadSafety();
demonstratePerformance();
demonstrateAlternatives();
}
public static void demonstrateBasicDifferences() {
System.out.println("\n--- 基本差异 ---");
// 1. 创建方式相同
Vector<String> vector = new Vector<>();
ArrayList<String> arrayList = new ArrayList<>();
// 2. 基本操作相同
vector.add("Vector Element");
arrayList.add("ArrayList Element");
System.out.println("Vector: " + vector);
System.out.println("ArrayList: " + arrayList);
// 3. Vector特有的方法
vector.addElement("Old Style Add"); // 旧式方法
System.out.println("Vector特有方法: " + vector);
// 4. 容量管理
System.out.println("\n容量管理:");
System.out.println("Vector初始容量: " + vector.capacity());
// ArrayList没有capacity()方法
// System.out.println("ArrayList初始容量: " + arrayList.capacity()); // 编译错误
// 5. 增长策略
System.out.println("\n增长策略差异:");
System.out.println("Vector: 每次增长100%(翻倍)");
System.out.println("ArrayList: 每次增长50%");
demonstrateGrowthStrategy();
}
private static void demonstrateGrowthStrategy() {
// 观察Vector的增长
Vector<Integer> vector = new Vector<>(2);
System.out.println("\nVector增长过程:");
System.out.println("初始容量: " + vector.capacity());
for (int i = 0; i < 10; i++) {
vector.add(i);
System.out.println("添加元素" + i + "后容量: " + vector.capacity());
}
}
public static void demonstrateThreadSafety() {
System.out.println("\n--- 线程安全性演示 ---");
Vector<Integer> vector = new Vector<>();
ArrayList<Integer> arrayList = new ArrayList<>();
// 线程安全测试
int threadCount = 10;
int operationsPerThread = 1000;
// 测试Vector(线程安全)
System.out.println("\n测试Vector线程安全性:");
testConcurrentAccess(vector, threadCount, operationsPerThread, "Vector");
// 测试ArrayList(非线程安全)
System.out.println("\n测试ArrayList线程安全性:");
testConcurrentAccess(arrayList, threadCount, operationsPerThread, "ArrayList");
// 使用同步包装器
System.out.println("\n使用同步包装器:");
List<Integer> synchronizedList = Collections.synchronizedList(new ArrayList<>());
testConcurrentAccess(synchronizedList, threadCount, operationsPerThread, "SynchronizedList");
}
private static void testConcurrentAccess(List<Integer> list, int threadCount,
int operationsPerThread, String listType) {
ExecutorService executor = Executors.newFixedThreadPool(threadCount);
CountDownLatch latch = new CountDownLatch(threadCount);
long startTime = System.currentTimeMillis();
for (int i = 0; i < threadCount; i++) {
final int threadId = i;
executor.submit(() -> {
try {
for (int j = 0; j < operationsPerThread; j++) {
list.add(threadId * operationsPerThread + j);
}
} finally {
latch.countDown();
}
});
}
try {
latch.await();
long endTime = System.currentTimeMillis();
System.out.println(listType + " 结果:");
System.out.println(" 期望大小: " + (threadCount * operationsPerThread));
System.out.println(" 实际大小: " + list.size());
System.out.println(" 耗时: " + (endTime - startTime) + "ms");
System.out.println(" 数据完整性: " +
(list.size() == threadCount * operationsPerThread ? "正确" : "错误"));
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
executor.shutdown();
}
}
public static void demonstratePerformance() {
System.out.println("\n--- 性能比较 ---");
int size = 1000000;
// 1. 添加性能
System.out.println("\n1. 添加性能测试:");
Vector<Integer> vector = new Vector<>();
long startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
vector.add(i);
}
long vectorTime = System.nanoTime() - startTime;
ArrayList<Integer> arrayList = new ArrayList<>();
startTime = System.nanoTime();
for (int i = 0; i < size; i++) {
arrayList.add(i);
}
long arrayListTime = System.nanoTime() - startTime;
System.out.println("Vector添加耗时: " + vectorTime / 1000000 + "ms");
System.out.println("ArrayList添加耗时: " + arrayListTime / 1000000 + "ms");
System.out.println("ArrayList比Vector快: " +
String.format("%.2f", (double) vectorTime / arrayListTime) + "倍");
// 2. 访问性能
System.out.println("\n2. 随机访问性能测试:");
Random random = new Random();
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
vector.get(random.nextInt(vector.size()));
}
long vectorGetTime = System.nanoTime() - startTime;
startTime = System.nanoTime();
for (int i = 0; i < 100000; i++) {
arrayList.get(random.nextInt(arrayList.size()));
}
long arrayListGetTime = System.nanoTime() - startTime;
System.out.println("Vector访问耗时: " + vectorGetTime / 1000000 + "ms");
System.out.println("ArrayList访问耗时: " + arrayListGetTime / 1000000 + "ms");
System.out.println("\n性能差异原因:");
System.out.println("- Vector的所有方法都是synchronized的");
System.out.println("- 同步开销导致性能下降");
System.out.println("- 单线程环境下ArrayList更优");
}
public static void demonstrateAlternatives() {
System.out.println("\n--- 现代替代方案 ---");
// 1. CopyOnWriteArrayList - 读多写少场景
System.out.println("\n1. CopyOnWriteArrayList (读多写少):");
CopyOnWriteArrayList<String> cowList = new CopyOnWriteArrayList<>();
cowList.add("Item 1");
cowList.add("Item 2");
// 迭代过程中修改不会抛出异常
for (String item : cowList) {
System.out.println("读取: " + item);
if ("Item 1".equals(item)) {
cowList.add("Item 3"); // 安全的并发修改
}
}
System.out.println("最终内容: " + cowList);
// 2. Collections.synchronizedList
System.out.println("\n2. Collections.synchronizedList:");
List<String> syncList = Collections.synchronizedList(new ArrayList<>());
syncList.add("Sync Item 1");
syncList.add("Sync Item 2");
// 注意:迭代时仍需要手动同步
synchronized (syncList) {
for (String item : syncList) {
System.out.println("同步访问: " + item);
}
}
// 3. 使用并发集合
System.out.println("\n3. 并发集合推荐:");
System.out.println("- ConcurrentLinkedQueue: 并发队列");
System.out.println("- CopyOnWriteArrayList: 读多写少的列表");
System.out.println("- ConcurrentHashMap: 并发Map");
System.out.println("\n选择建议:");
System.out.println("- 单线程: 使用ArrayList");
System.out.println("- 多线程读多写少: 使用CopyOnWriteArrayList");
System.out.println("- 多线程频繁写: 使用ConcurrentLinkedQueue");
System.out.println("- 需要同步的List: 使用Collections.synchronizedList");
System.out.println("- 避免使用Vector(除非维护遗留代码)");
}
}
本章小结
本章详细介绍了Java集合框架的核心内容:
集合框架概述:
- Collection和Map接口层次结构
- 泛型在集合中的应用
- 通配符和有界泛型的使用
List接口实现:
- ArrayList:基于动态数组,随机访问快,适合读多写少
- LinkedList:基于双向链表,头尾操作快,适合频繁插入删除
- Vector:同步的ArrayList,性能较差,现代开发中较少使用
性能特征:
- ArrayList:O(1)随机访问,O(n)中间插入
- LinkedList:O(1)头尾操作,O(n)随机访问
- Vector:同步开销导致性能下降
使用场景:
- 数据存储和检索
- 缓存实现
- 撤销/重做功能
- 播放列表等动态列表
下一章预告
下一章我们将继续学习Set接口和Map接口的实现类,包括HashSet、TreeSet、HashMap、TreeMap等。
练习题
- 实现一个支持撤销操作的文本编辑器
- 创建一个学生成绩管理系统,支持排序和筛选
- 实现一个简单的LRU缓存
- 比较ArrayList和LinkedList在不同场景下的性能