Java 的 Collections
工具类提供了一系列静态方法用于操作或返回集合。通过这些方法,我们可以进行排序、查找、替换以及同步控制等操作。在面试中,熟练掌握并能详细讲解这些操作,无疑会增加你的竞争力。本文将通过具体的代码示例和源码解析,深入讲解 Collections
工具类的常用方法。
排序操作
1. reverse(List list)
:反转列表
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class ReverseExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Collections.reverse(list);
System.out.println(list); // 输出: [3, 2, 1]
}
}
源码解析:
java
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 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);
}
}
}
这段代码展示了 reverse
方法的实现。对于支持快速随机访问的列表(如 ArrayList
),采用简单的交换方式进行反转。对于不支持快速随机访问的列表(如 LinkedList
),则采用双向迭代器来进行反转操作。
2. shuffle(List list)
:随机排序
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class ShuffleExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Collections.shuffle(list);
System.out.println(list); // 输出: [2, 1, 3](随机顺序)
}
}
源码解析:
java
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]);
}
}
}
shuffle
方法通过随机生成的索引来交换列表中的元素。对于支持快速随机访问的列表,直接交换元素;否则,将列表转换为数组进行操作,提高效率。
3. sort(List list)
:按自然排序的升序排序
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class SortExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(3);
list.add(1);
list.add(2);
Collections.sort(list);
System.out.println(list); // 输出: [1, 2, 3]
}
}
源码解析:
java
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
sort
方法调用了 List
接口的 sort
方法。如果没有提供比较器,则使用元素的自然顺序进行排序。
4. sort(List list, Comparator c)
:定制排序
java
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.ArrayList;
public class CustomSortExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("banana");
list.add("apple");
list.add("pear");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.compareTo(o1); // 按降序排序
}
});
System.out.println(list); // 输出: [pear, banana, apple]
}
}
定制排序通过提供一个 Comparator
实例,定义了自定义的排序逻辑。
5. swap(List list, int i, int j)
:交换元素
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class SwapExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Collections.swap(list, 0, 2);
System.out.println(list); // 输出: [3, 2, 1]
}
}
swap
方法简单地交换两个索引位置的元素,在源码中也被其他方法(如 reverse
和 shuffle
)频繁调用。
6. rotate(List list, int distance)
:旋转列表
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class RotateExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
list.add(5);
Collections.rotate(list, 2);
System.out.println(list); // 输出: [4, 5, 1, 2, 3]
}
}
源码解析:
java
public static void rotate(List<?> list, int distance) {
if (list instanceof RandomAccess || list.size() < ROTATE_THRESHOLD)
rotate1(list, distance);
else
rotate2(list, distance);
}
private static void rotate1(List<?> list, int distance) {
int size = list.size();
if (size == 0)
return;
distance = distance % size;
if (distance < 0)
distance += size;
if (distance == 0)
return;
for (int cycleStart = 0, nMoved = 0; nMoved != size; cycleStart++) {
Object displaced = list.get(cycleStart);
int i = cycleStart;
do {
i += distance;
if (i >= size)
i -= size;
displaced = list.set(i, displaced);
nMoved++;
} while (i != cycleStart);
}
}
rotate
方法将列表的元素整体移动一定距离,该方法对于支持快速随机访问的列表和不支持快速随机访问的列表采用不同的实现方式。
查找与替换操作
1. binarySearch(List list, Object key)
:二分查找
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class BinarySearchExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
list.add(9);
int index = Collections.binarySearch(list, 5);
System.out.println(index); // 输出: 2
}
}
二分查找要求列表必须是有序的,否则结果不确定。
2. max(Collection coll)
和 min(Collection coll)
:最大值和最小值
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class MaxMinExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(3);
list.add(5);
list.add(7);
list.add(9);
int max = Collections.max(list);
int min = Collections.min(list);
System.out.println("Max: " + max); // 输出: Max: 9
System.out.println("Min: " + min); // 输出: Min: 1
}
}
3. fill(List list, Object obj)
:替换所有元素
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class FillExample {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
Collections.fill(list, 0);
System.out.println(list); // 输出: [0, 0, 0]
}
}
4. frequency(Collection c, Object o)
:统计元素出现次数
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class FrequencyExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple");
list.add("apple");
list.add("pear");
int frequency = Collections.frequency(list, "apple");
System.out.println(frequency); // 输出: 3
}
}
5. indexOfSubList(List list, List target)
和 lastIndexOfSubList(List source, List target)
:子列表索引
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class SubListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple");
list.add("pear");
list.add("banana");
List<String> target = new ArrayList<>();
target.add("apple");
target.add("pear");
int index = Collections.indexOfSubList(list, target);
System.out.println(index); // 输出: 2
}
}
6. replaceAll(List list, Object oldVal, Object newVal)
:替换所有匹配的元素
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class ReplaceAllExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("apple");
list.add("banana");
list.add("apple");
Collections.replaceAll(list, "apple", "orange");
System.out.println(list); // 输出: [orange, banana, orange]
}
}
同步控制
虽然 Collections
提供的同步控制方法可以将非线程安全的集合包装成线程安全的集合,但这些方法性能较低。对于高并发场景,推荐使用 java.util.concurrent
包下的并发集合,如 ConcurrentHashMap
、CopyOnWriteArrayList
等。
java
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
public class SynchronizedListExample {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list = Collections.synchronizedList(list);
// 线程安全的操作
synchronized (list) {
list.add("apple");
list.add("banana");
}
}
}
上述代码展示了如何将 ArrayList
包装成线程安全的列表,但在高并发场景下,推荐使用 CopyOnWriteArrayList
。
java
import java.util.concurrent.CopyOnWriteArrayList;
public class ConcurrentListExample {
public static void main(String[] args) {
CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("apple");
list.add("banana");
}
}