为了账号安全,请及时绑定邮箱和手机立即绑定

Java Collections.sort() 未按预期排序

Java Collections.sort() 未按预期排序

沧海一幻觉 2021-10-20 16:04:29
我正在尝试按特定属性(“程序”的“学生”对象和“教师”的“教授”对象)对两个不同的对象数组列表进行排序。这两个类都扩展了我的抽象“人”类。public abstract class Person implements Comparable<Person>{    private String name;    private String adress;    //getters, setters, etc., all works properly    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();     }    public int compareTo(String string) {        return name.compareTo(string);    }}然后,当我创建一个由 1000000 个随机“人”对象组成的数组时,可以是学生或教授,我决定像这样按他们的名字按字母顺序排序(这可以正常工作)。Person personByName[] = arrayPersonas.clone();Arrays.sort(personByName);然后,我将原始 Person 数组划分为两个 ArrayList,一个用于 Student 对象,另一个用于教授对象:    ArrayList<Student> studentsByProgram = new ArrayList();    ArrayList<Professor> professorsByFaculty = new ArrayList();    for (int i = 0; i < 1000000; i++) {         if (arrayPersonas[i] instanceof Student) {            studentsByProgram.add((Student)arrayPersonas[i]);        } else {            professorsByFaculty.add((Professor)arrayPersonas[i]);        }    }当我尝试按我想要的属性按字母顺序对每个 ArrayList 进行排序时,问题就出现了,因为它一直按 Person 的名称对它们进行排序:Collections.sort(studentsByProgram);Collections.sort(professorsByFaculty);在这里,我离开我的学生和教授课程:public class Student extends Person {    private String program;    private int year;    private double fee;    //constructor, setters, getters, toString, equals    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();     }    public int compareTo(String string) {        return program.compareTo(string);     }    @Override    public int compareTo(Person t) {        return super.compareTo(t.getName());    }}教授班:public class Professor extends Person {    private String faculty;    private double salary;    //constructor, setters, getters, toString, equals    @Override    protected Object clone() throws CloneNotSupportedException {        return super.clone();     }    public int compareTo(String string) {        return faculty.compareTo(string);     }
查看完整描述

3 回答

?
繁花不似锦

TA贡献1851条经验 获得超4个赞

您有两个不同的 compareTo() 方法。Collections.sort() 不会调用您期望使用的那个。

如果您想使用 Collections.sort() 对学生进行排序,那么您需要一个带有签名的方法 compareTo(Student student);

此方法与 compareTo(Person person) “重叠”,这是两个方面的问题:

  • 从语义上讲,Person 级别的 compareTo() 方法建立了语义,而 Student 级别的 compareTo() 方法偏离了这些语义,这绝不是一个好主意。

  • 从技术上讲,您依赖于与方法绑定相关的实现细节来使您的系统按预期运行。这充其量是狡猾的。

我会寻找一种使用显式用户提供的比较器而不是依赖于内部 compareTo() 的排序方法的排序方法。


查看完整回答
反对 回复 2021-10-20
?
慕田峪9158850

TA贡献1794条经验 获得超7个赞

问题

  1. 您没有定义Person应该如何比较对象。

  2. 您错误地定义了如何比较StudentProfessor实例。

  3. 您编写compareTo(String)了具有误导性的重载方法。

解决方案

Person#compareTo正确定义,删除其compareTo(String):


public int compareTo(Person p) {

    return getName().compareTo(p.getName());

}

定义Student#compareTo并Professor#compareTo正确删除它们的compareTo(String). 这是一个如何Student#compareTo编写的示例:


@Override

public int compareTo(Person t) {

    final int personComparisonResult = super.compareTo(t);


    if (personComparisonResult == 0) {

        return program.compareTo(((Student) t).program);

    }


    return personComparisonResult;

}

它说“首先将它们作为Persons进行比较;如果它们相等(此处为同名),则将它们作为Students进行比较(此处为学生的程序)”。


我会删除这些方法。对于不适合类域的简单代码行使用单独的方法是不值得的。


查看完整回答
反对 回复 2021-10-20
?
POPMUISE

TA贡献1765条经验 获得超5个赞

如果要使用与类“自然”排序不同的排序对对象进行排序,则应该使用Arrays.sort(T[], Comparator<T>), 和一个Comparator实现特定排序顺序的对象。

javadoc的用于Comparable解释说,它应该实现的语义。(仔细阅读它们!)

关于自然排序:

  • Person[]compareTo(Person)方法给出的遗嘱的“自然”排序。

  • Student[](或ArrayList<Student>)的“自然”排序将由该compareTo(Student)方法给出。

  • 等等。

  • 在这些情况下都compareTo(String)不会使用您的方法!


查看完整回答
反对 回复 2021-10-20
  • 3 回答
  • 0 关注
  • 196 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信