为什么我们在 Comparable 实现中的 CompareTo 中使用 `this`?

Why do we use `this` in CompareTo in Comparable implementations?

我对 java 有点陌生,对 Collection 框架也很陌生。我知道this指的是当前对象

public class Student implements Comparable <Student> {

    String name;
    int grade;

    public Student(String name, int grade) {
        this.name = name;
        this.grade = grade;
    }
    public int compareTo(Student s) {
         return this.name.compareTo(s.name);
    }
    public String toString() {
        return this.name + ", " + this.grade;
    }
}

此处 this.name 为 null 而 s.name 确实有一个值,那么我们通过比较 this.name.compareTo(s.name);

来尝试做什么

还有当我们做 Collections.sort(studentList); 时到底发生了什么?

代码片段仅用于演示目的

你问的是两个不同的问题,我会分开回答

第一个是 我们要通过比较 this.name.compareTo(s.name);

当对 class Student 的对象调用 compareTo 方法时,this 成为调用对象。由于调用对象(希望如此)已正确初始化,this.name 将是调用对象的名称。

s.name 是传递给 compareTo 方法的 Student 对象的名称,该方法再次(希望)正确初始化并具有名称。

归结起来就是一个String变量调用compareTo传入一个String变量来比较

其次是 当我们执行 Collections.sort(studentList);

时真正发生的事情

这是 Collections.Sort method 上的 JavaDocs,但您可能会问它相对于您的 Comparable 实现做了什么。简而言之,它在对 sort

进行比较时使用您的 compareTo 方法

既然 name 似乎是 Student 中的一个重要 属性,您应该首先问自己 "What is a valid name for a student?" null 是否有效?空字符串有效吗?如果不是,您需要使用 setter:

来防止 Student 初始化为无效的 name
public void setName(String name) {
  if (name is invalid) {
    throw error;
  }

  this.name = name; // name is valid, so this is safe now
}

现在,在您的构造函数中调用 setter,您将确定如果您有一个 Student,他将有一个有效的 name

无效 name 的一个问题是,如果您不阻止 null 值,您每次调用 compareTo() 时都会得到 NullPointerException方法。你基本上会调用 null.compareTo() 并且显然 null 没有这样的方法,它没有任何方法。

现在,进入 sort() 方法。您如何对 Student 进行排序?如果您不告诉 Java 如何将一个 Student 与另一个 Student 进行比较,它应该如何排序?它可以处理数字(2 小于 3)和字符串("a" 在 "b" 之前),但它不知道如何比较您创建的自定义 class。因此,你需要让它知道——使用 compareTo() 方法。对无法比较的对象集合调用 sort() 将导致异常。在 Student 的集合上调用 sort() 将使用您在 compareTo() 中提供的规则对它们进行排序,即 name(常规字符串比较)。

至于排序机制本身,它是特定于实现的,但它通常是几种算法的组合,一种混合​​。在 Java 中,我相信它是 Timsort,在 C# 中,它是内省的。无论如何,为了像这样对集合进行排序,您需要两个两个地比较元素(因此需要实现 Comparable)。诀窍是如何做到这一点,以减少执行的比较次数。有很多很好的资源可以解释不同的排序方法,但归根结底是能够比较元素并判断哪个应该在哪个之前。