前言
早期开发者经常需要对集合进行各种操作
比如排序、查找最大最小值等等
但是当时没有统一的工具类来处理
所以导致代码重复且容易出错
java.util.Collections 工具类的引入
为开发者提供了大量 静态方法 来操作集合
它就像一个经验丰富的助手
和数组工具类 Arrays 一样
避免了我们重复造轮子的情况
一、Collections 工具类概述
java.util.Collections 是一个操作集合的工具类
提供大量 静态方法 来 操作 或 返回 集合
源码:
// Collections 类的声明
public class Collections {
// 私有构造函数,防止实例化
private Collections() {
}
// ... 大量静态方法
}
通过源码我们可以看出:
- Collections 是一个很纯粹的工具类
- 没有继承,没有实现,父类是 Object
- 构造器私有,不能实例化对象
注意区分:
Collections 是集合的工具类
Collection 是单列集合的根接口
二、核心方法
1、addAll
方法声明:
public static <T> boolean addAll(Collection<? super T> c, T... elements)
调用者:
Collections
参数:
Collection<? super T>c :目标集合
T...elements :要添加的元素(可变参)
泛型中,我们常见三种形式:
1、T 具体类型参数
2、?extends T 上界通配符,表示T或T的子类型
3、?super T 下界通配符,表示T或T的父类型
返回值:
boolean,如果集合被修改则返回true
作用:
将多个元素一次性添加到集合中
是否改变原始值:
是,会修改目标集合
源码:
public static <T> boolean addAll(Collection<? super T> c, T... elements) {
boolean result = false;
for (T element : elements)
result |= c.add(element);
return result;
}
源码解读:
- 使用可变参 T...elements 接收任意数量的元素
- 遍历所有元素,逐个添加到集合中
- 使用 位或运算 |= 累计添加结果,只要有元素成功添加就返回true
示例:
import java.util.*;
public class AddAllExample {
public static void main(String[] args) {
List<String> fruits = new ArrayList<>();
// 使用 Collections.addAll 批量添加元素
Collections.addAll(fruits, "apple", "banana", "orange", "grape");
System.out.println("水果列表: " + fruits);
// 输出: 水果列表: [apple, banana, orange, grape]
// 对比传统方式
List<String> vegetables = new ArrayList<>();
vegetables.add("carrot");
vegetables.add("potato");
vegetables.add("tomato");
System.out.println("蔬菜列表: " + vegetables);
// 输出: 蔬菜列表: [carrot, potato, tomato]
}
}
2、sort
方法声明:
//自然排序版本
public static <T extends Comparable<? super T>> void sort(List<T> list)
//比较器排序版本
public static <T> void sort(List<T> list, Comparator<? super T> c)
调用者:
Collections
参数:
List<T> list:要排序的列表
Comparator<?super T>c:比较器(可选)
返回值:
void
作用:
对列表进行排序
是否改变原始值:
是,会修改原列表
注意事项:
自然排序要求实现 Comparable 接口
源码:
// 自然排序版本
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
// 比较器排序版本
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
源码解读:
实际上是委托给 List 接口的 sort 方法实现
JDK 8 之后,List 接口增加了默认方法 sort,Collections.sort 成为了该方法的包装
JDK 8 之前 Collections.sort() 实现:
// JDK 8 之前的 Collections.sort() 实现(简化版) public static <T extends Comparable<? super T>> void sort(List<T> list) { Object[] a = list.toArray(); Arrays.sort(a); ListIterator<T> i = list.listIterator(); for (int j=0; j<a.length; j++) { i.next(); i.set((T)a[j]); } }
JDK 8 之后 List 接口新增的默认方法:
// List 接口中的默认方法 sort() default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (int j=0; j<a.length; j++) { i.next(); i.set((E) a[j]); } }
JDK 8 之后 Collections.sort() 实现:
// JDK 8 之后 Collections.sort() 的实现(简化版) public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); // 委托给 List.sort() 方法 } public static <T> void sort(List<T> list, Comparator<? super T> c) { list.sort(c); // 委托给 List.sort() 方法 }
总结一下:
- 功能转移:排序核心功能被转移到了 List 接口中
- 实现委托:Collections.sort() 方法现在内部调用 List.sort() 来实现排序功能
示例:
import java.util.*;
public class SortExample {
public static void main(String[] args) {
// 自然排序示例
List<Integer> numbers = new ArrayList<>();
Collections.addAll(numbers, 5, 2, 8, 1, 9);
System.out.println("排序前: " + numbers);
Collections.sort(numbers); // 自然排序
System.out.println("自然排序后: " + numbers);
// 输出: 自然排序后: [1, 2, 5, 8, 9]
// 比较器排序示例(降序)
List<String> words = new ArrayList<>();
Collections.addAll(words, "banana", "apple", "cherry");
System.out.println("排序前: " + words);
Collections.sort(words, Collections.reverseOrder()); // 降序排序
System.out.println("降序排序后: " + words);
// 输出: 降序排序后: [cherry, banana, apple]
}
}
3、reverse
方法声明:
public static void reverse(List<?> list)
调用者:
Collections
参数:
List<?> list :要反转的列表
返回值:
void
作用:
反转集合中的元素顺序
是否改变原始值:
是,会修改原集合
注意事项:
只适用于 List 类型的集合
源码:
public static void reverse(List<?> list) {
int size = list.size();
if (size < REVERSE_THRESHOLD || list instanceof RandomAccess) {
// 对于小列表或随机访问列表,直接交换元素
for (int i=0, mid=size>>1, j=size-1; i<mid; i++, j--)
swap(list, i, j);
} else {
// 对于大列表且非随机访问,使用ListIterator
ListIterator fwd = list.listIterator();
ListIterator rev = list.listIterator(size);
for (int i=0, mid=list.size()>>1; i<mid; i++) {
Object tmp = fwd.next();
fwd.set(rev.previous());
rev.set(tmp);
}
}
}
源码解读:
- 根据列表大小和是否实现 RandomAccess 接口选择不同的实现策略
- 小列表或者随机访问列表采用直接索引交换的方式
- 大列表且非随机访问采用 LIstIterator
示例:
import java.util.*;
public class ReverseExample {
public static void main(String[] args) {
List<String> colors = new ArrayList<>();
Collections.addAll(colors, "red", "green", "blue", "yellow");
System.out.println("反转前: " + colors);
// 输出: 反转前: [red, green, blue, yellow]
Collections.reverse(colors);
System.out.println("反转后: " + colors);
// 输出: 反转后: [yellow, blue, green, red]
}
}
4、shuffle
方法声明:
public static void shuffle(List<?> list)
public static void shuffle(List<?> list, Random rnd)
调用者:
Collections
参数:
List<?> list:要打乱的集合
Random rnd:随机数生成器(可选)
返回值:
void
作用:
随机打乱列表中的元素顺序
是否改变原始值:
是,会修改原集合
注意事项:
可以传入自定义的Random对象以控制随机种子
源码:
public static void shuffle(List<?> list) {
Random rnd = r;
if (rnd == null)
r = rnd = new Random();
shuffle(list, rnd);
}
public static void shuffle(List<?> list, Random rnd) {
int size = list.size();
if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
for (int i=size; i>1; i--)
swap(list, i-1, rnd.nextInt(i));
} else {
Object arr[] = list.toArray();
for (int i=size; i>1; i--)
swap(arr, i-1, rnd.nextInt(i));
ListIterator it = list.listIterator();
for (int i=0; i<arr.length; i++) {
it.next();
it.set(arr[i]);
}
}
}
源码解读:
- 使用 Fisher-Yates 洗牌算法实现随机打乱
- 根据列表大小和是否实现 RandomAccess 接口选择不同的实现策略
示例:
import java.util.*;
public class ShuffleExample {
public static void main(String[] args) {
List<Integer> cards = new ArrayList<>();
for (int i = 1; i <= 10; i++) {
cards.add(i);
}
System.out.println("洗牌前: " + cards);
Collections.shuffle(cards);
System.out.println("洗牌后: " + cards);
// 使用固定种子的随机数生成器
Collections.shuffle(cards, new Random(123));
System.out.println("固定种子洗牌: " + cards);
}
}
5、max/min
方法声明:
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
调用者:
Collections
参数:
Collection<? extends T> coll:要查找的集合
Comparator<? super T> comp:比较器(可选)
返回值:
T,集合中的最大或最小元素
作用:
查找集合中的最大或最小元素
是否改变原始值:
否,不修改原集合
注意事项:
自然排序要求实现 Comparable 接口
空集合会抛出 NoSuchElementException
源码:
public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll) {
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (next.compareTo(candidate) < 0)
candidate = next;
}
return candidate;
}
public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp) {
if (comp==null)
return (T)min((Collection) coll);
Iterator<? extends T> i = coll.iterator();
T candidate = i.next();
while (i.hasNext()) {
T next = i.next();
if (comp.compare(next, candidate) < 0)
candidate = next;
}
return candidate;
}
源码解读:
- 通过迭代器遍历集合,比较元素大小
- 自然排序使用 compareTo 方法,比较器排序使用 compare 方法
示例:
import java.util.*;
public class MaxMinExample {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<>();
Collections.addAll(numbers, 10, 5, 8, 3, 15, 7);
Integer max = Collections.max(numbers);
Integer min = Collections.min(numbers);
System.out.println("数字列表: " + numbers);
System.out.println("最大值: " + max); // 输出: 最大值: 15
System.out.println("最小值: " + min); // 输出: 最小值: 3
// 使用自定义比较器(按绝对值比较)
List<Integer> negativeNumbers = new ArrayList<>();
Collections.addAll(negativeNumbers, -10, 5, -8, 3);
// 按绝对值找最大值
Integer maxAbs = Collections.max(negativeNumbers, Comparator.comparing(Math::abs));
System.out.println("绝对值最大: " + maxAbs); // 输出: 绝对值最大: -10
}
}
6、fill
方法声明:
public static <T> void fill(List<? super T> list, T obj)
调用者:
Collections
参数:
List<? super T> list:要填充的集合
T obj:用于填充的对象
返回值:
void
作用:
使用指定的元素替换集合中的所有元素
是否改变原始值:
是,会修改原集合
注意事项:
集合必须已经有元素,不能是空列表
源码:
public static <T> void fill(List<? super T> list, T obj) {
int size = list.size();
if (size < FILL_THRESHOLD || list instanceof RandomAccess) {
for (int i=0; i<size; i++)
list.set(i, obj);
} else {
ListIterator<? super T> itr = list.listIterator();
for (int i=0; i<size; i++) {
itr.next();
itr.set(obj);
}
}
}
源码解读:
- 根据列表大小和是否实现 RandomAccess 接口选择不同的实现策略
- 使用索引或迭代器将所有元素替换为指定对象
示例:
import java.util.*;
public class FillExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>(Arrays.asList(new String[5]));
System.out.println("填充前: " + list);
Collections.fill(list, "default");
System.out.println("填充后: " + list);
// 输出: 填充后: [default, default, default, default, default]
// 也可以用于初始化
List<Integer> numbers = new ArrayList<>(Collections.nCopies(5, 0));
System.out.println("初始化: " + numbers);
Collections.fill(numbers, 1);
System.out.println("填充为1: " + numbers);
}
}
7、binarySearch
方法声明:
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key)
private static <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key)
调用者:
Collections
参数:
List<? extends Comparable<? super T>> list:已降序的集合
T key:要查找的键
Comparator<? super T> c:比较器(可选)
返回值:
int,找到则返回索引,未找到则返回负数
作用:
在已排序集合中查找指定元素
是否改变原始值:
否,不修改原集合
注意事项:
集合必须已经排序
返回值为负数时表示未找到,其绝对值减 1 是应该插入的位置
源码:
public static <T> int binarySearch(List<? extends Comparable<? super T>> list, T key) {
if (list instanceof RandomAccess || list.size()<BINARYSEARCH_THRESHOLD)
return Collections.indexedBinarySearch(list, key);
else
return Collections.iteratorBinarySearch(list, key);
}
private static <T> int indexedBinarySearch(List<? extends Comparable<? super T>> list, T key) {
int low = 0;
int high = list.size()-1;
while (low <= high) {
int mid = (low + high) >>> 1;
Comparable<? super T> midVal = list.get(mid);
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found
}
源码解读:
- 实现标准的二分查找算法
- 根据列表是否实现 RandomAccess 接口选择不同的实现策略
示例:
import java.util.*;
public class BinarySearchExample {
public static void main(String[] args) {
List<Integer> sortedList = new ArrayList<>();
Collections.addAll(sortedList, 1, 3, 5, 7, 9, 11, 13);
int index = Collections.binarySearch(sortedList, 7);
System.out.println("元素7的索引: " + index); // 输出: 元素7的索引: 3
int notFoundIndex = Collections.binarySearch(sortedList, 6);
System.out.println("元素6的索引: " + notFoundIndex); // 输出: 元素6的索引: -4
System.out.println("应该插入的位置: " + (Math.abs(notFoundIndex) - 1)); // 输出: 应该插入的位置: 3
}
}