为什么我们在 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
)。诀窍是如何做到这一点,以减少执行的比较次数。有很多很好的资源可以解释不同的排序方法,但归根结底是能够比较元素并判断哪个应该在哪个之前。
我对 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
)。诀窍是如何做到这一点,以减少执行的比较次数。有很多很好的资源可以解释不同的排序方法,但归根结底是能够比较元素并判断哪个应该在哪个之前。