如何编写一个比较对象的compareTo方法?

29

我正在学习数组,我的一个数组包含一个姓氏,名字和分数。

我需要编写一个compareTo方法来比较姓氏和名字,以便可以按姓氏的字母顺序排序,如果两个人有相同的姓氏,则按名字排序。

我感到困惑,因为我书中的所有信息都是比较数字,而不是对象和字符串。

以下是我目前编写的代码。我知道它是错误的,但至少解释了我认为自己在做什么:

public int compare(Object obj) // creating a method to compare 
{   
    Student s = (Student) obj; // creating a student object

    // I guess here I'm telling it to compare the last names?
    int studentCompare = this.lastName.compareTo(s.getLastName()); 

    if (studentCompare != 0)
        return studentCompare;
    else 
    {
        if (this.getLastName() < s.getLastName())
            return - 1;

        if (this.getLastName() > s.getLastName())
            return 1;
    }
    return 0;
}

我知道 <> 符号是错误的,但是就像我说的,我的书只告诉你如何使用 compareTo


如果你只是说someString < someOtherString,那就没有太大必要用到compareTo了... - cHao
9个回答

24

这是比较字符串的正确方法:

int studentCompare = this.lastName.compareTo(s.getLastName()); 
这段代码甚至无法编译:
if (this.getLastName() < s.getLastName())

使用 if (this.getLastName().compareTo(s.getLastName()) < 0) 替代。

因此,要比较名字的姓和名的顺序,您需要:

int d = getFirstName().compareTo(s.getFirstName());
if (d == 0)
    d = getLastName().compareTo(s.getLastName());
return d;

我同意你构建if语句的方式。第一个会出现错误。 - LatheElHafy
那么,所有的compareTo(),equals()和hashCode()都只使用原始类型进行比较,覆盖equals并计算hashCode?它不能使用非原始类型完成。我的理解是正确的吗? - sofs1
是的,如果你的问题是针对非原始类型,你不能使用“>”,“<”和“==”。 - Eugene Retunsky

18

compareTo方法的描述如下:

将此对象与指定对象进行比较以进行排序。如果此对象小于、等于或大于指定对象,则返回负整数、零或正整数。

假设我们想通过Jedi的年龄来进行比较:

class Jedi implements Comparable<Jedi> {

    private final String name;
    private final int age;
        //...
}

如果我们的绝地武士比给定的年龄大,你必须返回一个正数;如果年龄相同,则返回0;如果我们的绝地武士比给定的年龄小,返回一个负数。

public int compareTo(Jedi jedi){
    return this.age > jedi.age ? 1 : this.age < jedi.age ? -1 : 0;
}
通过实现Comparable接口中的compareTo方法,你可以定义所谓的“自然顺序”。JDK中的所有排序方法都将默认使用这个顺序。有时候,你可能希望基于其他对象而不是原始类型进行比较。例如,根据名称比较Jedis。在这种情况下,如果被比较的对象已经实现了Comparable接口,那么可以使用其compareTo方法进行比较。
public int compareTo(Jedi jedi){
    return this.name.compareTo(jedi.getName());
}

在这种情况下,这样做会更简单。

现在,如果你打算同时使用名称和年龄作为比较标准,那么你必须决定比较的顺序,什么更具有优先权。例如,如果两个绝地武士的名字相同,那么你可以使用他们的年龄来决定谁先谁后。

public int compareTo(Jedi jedi){
    int result = this.name.compareTo(jedi.getName());
    if(result == 0){
        result = this.age > jedi.age ? 1 : this.age < jedi.age ? -1 : 0;
    }
    return result;
}

如果您有一个Jedis数组

Jedi[] jediAcademy = {new Jedi("Obiwan",80), new Jedi("Anakin", 30), ..}

你只需要向java.util.Arrays类请求使用它的排序方法即可。

Arrays.sort(jediAcademy);

这个Arrays.sort方法将使用你的compareTo方法逐一对对象进行排序。


另外,您可以选择通过交换-1、1的返回值来按升序或降序显示列表的顺序。 - fardown

2

听取 @milkplusvellocet 的建议,我建议您还要为您的类实现 Comparable 接口。

只是对其他答案的贡献:

String.compareTo() 会告诉你一个字符串与另一个字符串有多不同。

例如 System.out.println( "Test".compareTo("Tesu") ); 将打印 -1 和 System.out.println( "Test".compareTo("Tesa") ); 将打印 19

而这个任务的书呆子和极客一行解决方案是:

return this.lastName.equals(s.getLastName()) ? this.lastName.compareTo(s.getLastName()) : this.firstName.compareTo(s.getFirstName());

解释:

this.lastName.equals(s.getLastName()) 检查姓氏是否相同 this.lastName.compareTo(s.getLastName()) 如果是,则返回姓氏比较结果。 this.firstName.compareTo(s.getFirstName()) 如果不是,则返回名字比较结果。


1

if (s.compareTo(t) > 0)将比较字符串s和字符串t,并返回您想要的整数值。

    public int Compare(Object obj) // creating a method to compare {   
        Student s = (Student) obj; //creating a student object

        // compare last names
        return  this.lastName.compareTo(s.getLastName());    
    }

现在只需像平常一样从该方法中测试正负返回即可。

谢谢。


1

你已经接近成功了。

你的前几行关于比较姓氏的方法是正确无误的。字符串的compareTo()方法会对按字母顺序排列在之前的字符串返回负数,而对按字母顺序排列在之后的字符串返回正数。

现在,你只需要对名字和分数做同样的事情。

换句话说,如果姓1 == 姓2,则继续检查下一个名字。如果名字相同,请检查分数。(考虑嵌套if/then块)


那么你的意思是说,我不需要从if(studentcompare !=0)开始的代码,因为上面一行已经返回了正数和负数了吗? - Jeremy B

1

考虑使用这里描述的泛型Comparator接口,这样您就可以避免将Object强制转换为Student

正如Eugene Retunsky所说,您的第一部分是比较String的正确方法。此外,如果lastName相等,则应该比较firstName,在这种情况下,只需以相同的方式使用compareTo即可。


0
一个字符串是Java中的一个对象。 你可以这样进行比较,
if(this.lastName.compareTo(s.getLastName() == 0)//last names are the same

0

我不会使用Object类型参数,因为我们知道它始终是Student类型,所以将其强制转换为Student没有意义。

至于解释,“result == 0”仅在姓氏相同时发生,在这种情况下,我们比较名字并返回该值。

public int Compare(Object obj)
{       
    Student student = (Student) obj;
    int result = this.getLastName().compareTo( student.getLastName() );

    if ( result == 0 )
    {
        result = this.getFirstName().compareTo( student.getFirstName() );
    }

    return result;
}

0
如果您在任何类中使用Comparable接口的compareTo方法,则可以使用它来按字典顺序排列字符串。
public class Student() implements Comparable<Student>{

public int compareTo(Object obj){
if(this==obj){
    return 0;
}
if(obj!=null){
    String objName = ((Student)obj).getName();
    return this.name.comapreTo.(objName);
}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接