【Java】泛型与集合篇 —— Collections 类

Collections 类

Collections 类是 Java 集合框架中的一个工具类,位于 java.util 包下。它提供了一系列静态方法,用于对集合(如 List、Set、Map 等)进行各种操作,包括排序、查找、重排、求极值以及其他方法等。

排序

  • 自然排序:sort(List<T> list)
    • 原理
      此方法用于对实现了 Comparable 接口的元素组成的 List 集合进行自然排序。Comparable 接口定义了一个 compareTo 方法,元素通过该方法来确定自身与其他元素的大小关系。排序时,Collections.sort 方法会调用元素的 compareTo 方法进行比较和排序。
  • 自定义排序:sort(List<T> list, Comparator<? super T> c)
    • 原理
      当元素没有实现 Comparable 接口,或者需要按照不同于自然顺序的规则进行排序时,可以使用该方法。通过传入一个 Comparator 接口的实现类,Comparator 接口定义了一个 compare 方法,用于比较两个元素的大小。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

// 定义一个实现了 Comparable 接口的类,用于自然排序演示
class Student implements Comparable<Student> {
    private String name;
    private int age;

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    // 重写 compareTo 方法,按照年龄进行自然排序
    @Override
    public int compareTo(Student other) {
        return Integer.compare(this.age, other.age);
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', age=" + age + "}";
    }
}

// 定义一个普通类,用于自定义排序演示
class Course {
    private String courseName;
    private double price;

    public Course(String courseName, double price) {
        this.courseName = courseName;
        this.price = price;
    }

    public String getCourseName() {
        return courseName;
    }

    public double getPrice() {
        return price;
    }

    @Override
    public String toString() {
        return "Course{courseName='" + courseName + "', price=" + price + "}";
    }
}

public class CollectionsSortDemo {
    public static void main(String[] args) {
        // 自然排序演示
        List<Student> studentList = new ArrayList<>();
        studentList.add(new Student("Alice", 22));
        studentList.add(new Student("Bob", 20));
        studentList.add(new Student("Charlie", 25));

        System.out.println("自然排序前的学生列表:");
        for (Student student : studentList) {
            System.out.println(student);
        }

        // 使用 Collections.sort 进行自然排序
        Collections.sort(studentList);

        System.out.println("\n自然排序后的学生列表:");
        for (Student student : studentList) {
            System.out.println(student);
        }

        // 自定义排序演示
        List<Course> courseList = new ArrayList<>();
        courseList.add(new Course("Java Programming", 200.0));
        courseList.add(new Course("Python Basics", 150.0));
        courseList.add(new Course("Data Science", 300.0));

        System.out.println("\n自定义排序前的课程列表:");
        for (Course course : courseList) {
            System.out.println(course);
        }

        // 自定义比较器,按照课程价格从高到低排序
        Comparator<Course> priceComparator = (c1, c2) -> Double.compare(c2.getPrice(), c1.getPrice());
        // 使用 Collections.sort 进行自定义排序
        Collections.sort(courseList, priceComparator);

        System.out.println("\n自定义排序后的课程列表:");
        for (Course course : courseList) {
            System.out.println(course);
        }
    }
}

代码解释:

  1. 自然排序部分:
    • 定义了 Student 类并实现了 Comparable 接口,重写了 compareTo 方法,使其按照学生的年龄进行自然排序。
    • 创建了一个 Student 对象的列表 studentList,添加了几个学生对象。
    • 打印排序前的学生列表,然后使用 Collections.sort(studentList) 对其进行自然排序,最后打印排序后的学生列表。
  2. 自定义排序部分:
    • 定义了 Course 类,该类没有实现 Comparable 接口。
    • 创建了一个 Course 对象的列表 courseList,添加了几个课程对象。
    • 打印排序前的课程列表,然后创建了一个 Comparator 匿名实现,按照课程价格从高到低进行比较。
    • 使用 Collections.sort(courseList, priceComparator) 对课程列表进行自定义排序,最后打印排序后的课程列表。

查找

Collections 类提供了一些用于在集合中进行查找操作的静态方法,这些方法可以帮助我们在 List 等集合中高效地查找元素。下面详细介绍其中常用的查找方法。

  1. 二分查找:binarySearch
    • 方法签名
      int binarySearch(List<? extends Comparable<? super T>> list, T key)
      int binarySearch(List<? extends T> list, T key, Comparator<? super T> c)
    • 原理
      二分查找(Binary Search)是一种高效的查找算法,要求被查找的列表必须是有序的(按自然顺序或指定的比较器顺序)。该算法通过不断将搜索区间缩小一半,直到找到目标元素或确定目标元素不存在。
    • 参数解释
      • 第一个重载方法:适用于列表中的元素实现了 Comparable 接口的情况,使用元素的自然顺序进行查找。
      • 第二个重载方法:适用于需要自定义比较规则的情况,通过传入 Comparator 来指定元素的比较方式。
    • 返回值
      如果找到目标元素,返回其在列表中的索引;如果未找到,返回一个负数,该负数是 (-(插入点) - 1),其中插入点是指将元素插入到列表中保持有序的位置。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

public class BinarySearchExample {
    public static void main(String[] args) {
        // 自然顺序二分查找示例
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(3);
        numbers.add(5);
        numbers.add(7);
        numbers.add(9);

        int result1 = Collections.binarySearch(numbers, 5);
        System.out.println("查找 5 的结果索引: " + result1);

        int result2 = Collections.binarySearch(numbers, 6);
        System.out.println("查找 6 的结果索引: " + result2);

        // 自定义顺序二分查找示例
        List<String> strings = new ArrayList<>();
        strings.add("banana");
        strings.add("apple");
        strings.add("cherry");
        // 先排序
        Collections.sort(strings, Comparator.reverseOrder());

        int result3 = Collections.binarySearch(strings, "apple", Comparator.reverseOrder());
        System.out.println("自定义顺序查找 apple 的结果索引: " + result3);
    }
}
  1. 查找最大 / 最小元素:max 和 min
    • 方法签名
      public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll)
      public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp)
      public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll)
      public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp)
    • 原理
      max 方法用于查找集合中的最大元素,min 方法用于查找集合中的最小元素。可以使用元素的自然顺序(元素实现 Comparable 接口),也可以通过传入 Comparator 自定义比较规则。
    • 参数解释
      • 当使用自然顺序时,要求集合中的元素实现 Comparable 接口。
      • 当使用自定义比较规则时,需要传入一个 Comparator 对象。
    • 返回值
      返回集合中的最大或最小元素。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', score=" + score + "}";
    }
}

public class MaxMinExample {
    public static void main(String[] args) {
        // 自然顺序查找最大/最小元素示例
        List<Integer> numbers = new ArrayList<>();
        numbers.add(2);
        numbers.add(4);
        numbers.add(1);
        numbers.add(3);

        int maxNumber = Collections.max(numbers);
        int minNumber = Collections.min(numbers);
        System.out.println("最大的数字: " + maxNumber);
        System.out.println("最小的数字: " + minNumber);

        // 自定义顺序查找最大/最小元素示例
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 80));
        students.add(new Student("Bob", 90));
        students.add(new Student("Charlie", 70));

        Student highestScoreStudent = Collections.max(students, Comparator.comparingInt(Student::getScore));
        Student lowestScoreStudent = Collections.min(students, Comparator.comparingInt(Student::getScore));
        System.out.println("最高分的学生: " + highestScoreStudent);
        System.out.println("最低分的学生: " + lowestScoreStudent);
    }
}
  1. 注意事项
    • 二分查找要求有序:使用 binarySearch 方法时,必须确保列表是有序的,否则结果将不可靠。
    • 空集合处理:如果传入的集合为空,max 和 min 方法会抛出 NoSuchElementException 异常,在使用时需要进行空集合的判断。
    • null 元素处理:集合中不应该包含 null 元素,否则可能会导致 NullPointerException。

打乱元素次序

Collections 类提供了 shuffle 方法用于打乱集合中元素的次序,该方法可以随机重新排列 List 集合里元素的顺序。以下为你详细介绍这个方法。

  1. 方法签名及原理
    Collections 类提供了两种重载形式的 shuffle 方法:
    • public static void shuffle(List<?> list):使用默认的随机源(Random 对象)来打乱列表中元素的顺序。
    • public static void shuffle(List<?> list, Random rnd):使用指定的随机源 rnd 来打乱列表中元素的顺序,这样可以实现可重复的随机打乱效果(如果使用相同的随机种子初始化 Random 对象)。
  2. 示例代码
    以下是使用 shuffle 方法的示例代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class ShuffleExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        for (int i = 1; i <= 10; i++) {
            numbers.add(i);
        }

        System.out.println("打乱前的列表: " + numbers);

        // 使用默认随机源打乱列表元素
        Collections.shuffle(numbers);
        System.out.println("使用默认随机源打乱后的列表: " + numbers);

        // 使用指定随机源打乱列表元素
        Random random = new Random(123); // 使用固定种子,保证结果可重复
        Collections.shuffle(numbers, random);
        System.out.println("使用指定随机源打乱后的列表: " + numbers);
    }
}

代码解释

  • 创建列表:首先创建了一个包含从 1 到 10 的整数的 ArrayList,并打印出打乱前的列表内容。
  • 使用默认随机源打乱元素:调用 Collections.shuffle(numbers) 方法,该方法使用默认的 Random 对象来随机打乱列表中元素的顺序,然后打印出打乱后的列表。
  • 使用指定随机源打乱元素:创建一个 Random 对象并指定种子值为 123,调用 Collections.shuffle(numbers, random) 方法,使用这个指定的随机源来打乱列表元素。由于使用了固定的种子,每次运行代码时得到的打乱结果是相同的,这在需要可重复测试的场景中很有用。
  1. 注意事项
    • 线程安全问题:Collections.shuffle 方法本身不是线程安全的。如果在多线程环境下对同一个列表进行打乱操作,可能会导致数据不一致或抛出异常。若需要在多线程环境中使用,需要进行额外的同步处理。
    • 列表元素变更:shuffle 方法会直接修改传入的列表,而不会创建新的列表。因此,原列表的元素顺序会被改变。

求极值

Collections 类提供了 max 和 min 方法用于在集合中求极值,即找出集合里的最大元素和最小元素。下面从方法签名、使用示例、注意事项等方面详细介绍。

  1. 方法签名
    • 自然顺序求极值
      • public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll):用于在实现了 Comparable 接口的元素集合中,按照元素的自然顺序找出最大元素。
      • public static <T extends Object & Comparable<? super T>> T min(Collection<? extends T> coll):用于在实现了 Comparable 接口的元素集合中,按照元素的自然顺序找出最小元素。
    • 自定义顺序求极值
      • public static <T> T max(Collection<? extends T> coll, Comparator<? super T> comp):使用指定的 Comparator 来定义元素之间的比较规则,从而找出集合中的最大元素。
      • public static <T> T min(Collection<? extends T> coll, Comparator<? super T> comp):使用指定的 Comparator 来定义元素之间的比较规则,从而找出集合中的最小元素。
  2. 自然顺序求极值
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class NaturalOrderExtremumExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(10);
        numbers.add(5);
        numbers.add(20);
        numbers.add(15);

        // 求最大值
        Integer maxNumber = Collections.max(numbers);
        System.out.println("列表中的最大值: " + maxNumber);

        // 求最小值
        Integer minNumber = Collections.min(numbers);
        System.out.println("列表中的最小值: " + minNumber);
    }
}

在上述代码中,Integer 类实现了 Comparable 接口,所以可以直接使用 Collections.max 和 Collections.min 方法按照自然顺序找出列表中的最大和最小元素。

  1. 自定义顺序求极值
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

class Student {
    private String name;
    private int score;

    public Student(String name, int score) {
        this.name = name;
        this.score = score;
    }

    public int getScore() {
        return score;
    }

    @Override
    public String toString() {
        return "Student{name='" + name + "', score=" + score + "}";
    }
}

public class CustomOrderExtremumExample {
    public static void main(String[] args) {
        // 创建一个包含学生对象的列表
        List<Student> students = new ArrayList<>();
        students.add(new Student("Alice", 80));
        students.add(new Student("Bob", 90));
        students.add(new Student("Charlie", 70));

        // 自定义比较器,按分数比较
        Comparator<Student> scoreComparator = Comparator.comparingInt(Student::getScore);

        // 求分数最高的学生
        Student highestScoringStudent = Collections.max(students, scoreComparator);
        System.out.println("分数最高的学生: " + highestScoringStudent);

        // 求分数最低的学生
        Student lowestScoringStudent = Collections.min(students, scoreComparator);
        System.out.println("分数最低的学生: " + lowestScoringStudent);
    }
}

在这个示例中,Student 类没有实现 Comparable 接口,所以我们创建了一个 Comparator 对象 scoreComparator 来定义学生之间的比较规则(按分数比较),然后使用 Collections.max 和 Collections.min 方法根据这个自定义规则找出分数最高和最低的学生。

  1. 注意事项
    • 空集合处理:如果传入的集合为空,max 和 min 方法会抛出 NoSuchElementException 异常。在调用这些方法之前,应该先检查集合是否为空。
    • null 元素处理:集合中不应该包含 null 元素,否则在比较过程中可能会抛出 NullPointerException。在使用 max 和 min 方法之前,要确保集合中没有 null 元素。
    • 比较规则一致性:使用自定义 Comparator 时,要保证比较规则的一致性和传递性,否则可能会得到意外的结果。
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class EmptyCollectionExample {
    public static void main(String[] args) {
        List<Integer> emptyList = new ArrayList<>();
        if (!emptyList.isEmpty()) {
            Integer max = Collections.max(emptyList);
            System.out.println("最大值: " + max);
        } else {
            System.out.println("集合为空,无法求最大值。");
        }
    }
}

其他方法

Collections 类除了前面提到的排序、查找、打乱元素次序、求极值等方法外,还有许多其他常用方法,下面为你详细介绍。

  1. 反转列表元素顺序:reverse
    • 方法签名
      public static void reverse(List<?> list)
    • 功能
      该方法用于反转指定 List 集合中元素的顺序,即原本列表开头的元素会变为列表末尾的元素,反之亦然。
    • 示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class ReverseExample {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);

        System.out.println("反转前的列表: " + numbers);
        Collections.reverse(numbers);
        System.out.println("反转后的列表: " + numbers);
    }
}
  1. 交换列表中两个元素的位置:swap
    • 方法签名
      public static void swap(List<?> list, int i, int j)
    • 功能
      该方法用于交换指定 List 集合中索引为 i 和 j 的两个元素的位置。
    • 示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class SwapExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("apple");
        fruits.add("banana");
        fruits.add("cherry");
        fruits.add("date");

        System.out.println("交换前的列表: " + fruits);
        Collections.swap(fruits, 1, 3);
        System.out.println("交换后的列表: " + fruits);
    }
}
  1. 填充列表元素:fill
    • 方法签名
      public static <T> void fill(List<? super T> list, T obj)
    • 功能
      该方法用于将指定 List 集合中的所有元素替换为指定的对象 obj。
    • 示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class FillExample {
    public static void main(String[] args) {
        List<String> colors = new ArrayList<>();
        colors.add("red");
        colors.add("blue");
        colors.add("green");

        System.out.println("填充前的列表: " + colors);
        Collections.fill(colors, "yellow");
        System.out.println("填充后的列表: " + colors);
    }
}
  1. 复制列表元素:copy
    • 方法签名
      public static <T> void copy(List<? super T> dest, List<? extends T> src)
    • 功能
      该方法用于将源列表 src 中的所有元素复制到目标列表 dest 中。目标列表 dest 的长度必须至少等于源列表 src 的长度,否则会抛出 IndexOutOfBoundsException 异常。
    • 示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class CopyExample {
    public static void main(String[] args) {
        List<Integer> source = new ArrayList<>();
        source.add(1);
        source.add(2);
        source.add(3);

        List<Integer> destination = new ArrayList<>();
        for (int i = 0; i < source.size(); i++) {
            destination.add(0);
        }

        System.out.println("复制前的目标列表: " + destination);
        Collections.copy(destination, source);
        System.out.println("复制后的目标列表: " + destination);
    }
}
  1. 检查两个列表是否不相交:disjoint
    • 方法签名
      public static boolean disjoint(Collection<?> c1, Collection<?> c2)
    • 功能
      该方法用于检查两个集合 c1 和 c2 是否没有共同的元素。如果两个集合没有共同元素,则返回 true;否则返回 false。
    • 示例代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class DisjointExample {
    public static void main(String[] args) {
        List<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(2);
        list1.add(3);

        List<Integer> list2 = new ArrayList<>();
        list2.add(4);
        list2.add(5);
        list2.add(6);

        List<Integer> list3 = new ArrayList<>();
        list3.add(2);
        list3.add(7);
        list3.add(8);

        boolean isDisjoint12 = Collections.disjoint(list1, list2);
        boolean isDisjoint13 = Collections.disjoint(list1, list3);

        System.out.println("list1 和 list2 是否不相交: " + isDisjoint12);
        System.out.println("list1 和 list3 是否不相交: " + isDisjoint13);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值