【问题标题】:Java Collections.sort() not sorting as expectedJava Collections.sort() 未按预期排序
【发布时间】:2019-03-06 08:49:58
【问题描述】:

我正在尝试按特定属性对两个不同的对象 ArrayLists 进行排序(“程序”的“学生”对象和“教师”的“教授”对象)。这两个类都扩展了我的抽象“Person”类。

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 对象,另一个用于 Profess 对象:

    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 进行排序时,问题就出现了,因为它一直按人的名字对它们进行排序:

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); 
    }

    @Override
    public int compareTo(Person t) {
        return super.compareTo(t.getName());
    }
}

我做错了什么?我想如果我在学生对象的 ArrayList 上调用“Collections.sort()”,它将使用学生类中的“compareTo()”方法,该方法使用“程序”属性。我仍在学习使用这些方法,所以有些东西我没有得到。

【问题讨论】:

  • 那么,它发生时的功能是什么?你是不是按错误的顺序排序?
  • “我做错了什么?”不知道 - 会发生什么出乎意料的事情?
  • "当我尝试按我想要的属性按字母顺序对每个 ArrayList 进行排序时,问题就出现了,因为它一直按人的名称对它们进行排序:"
  • StudentProfessor 你有compareTo() 和字符串作为参数。您需要分别将其更改为 StudentProfessor
  • @Turamarth 做到了,它仍然按“名称”属性对 ArrayList 进行排序

标签: java sorting collections comparator comparable


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    【解决方案2】:

    问题

    1. 您没有定义应如何比较 Person 对象。
    2. 您错误地定义了应如何比较 StudentProfessor 实例。
    3. 您编写了具有误导性的重载方法compareTo(String)

    解决方案

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

      public int compareTo(Person p) {
          return getName().compareTo(p.getName());
      }
      
    2. 正确定义Student#compareToProfessor#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 进行比较(此处为学生程序)”。

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

    【讨论】:

    • 这与我想要做的事情完美配合,谢谢安德鲁
    【解决方案3】:

    如果您想使用与类“自然”排序不同的排序对对象进行排序,则应使用Arrays.sort(T[], Comparator&lt;T&gt;),以及实现特定排序或排序的Comparator 对象。

    Comparablejavadoc 解释了它应该实现的语义。 (仔细阅读!)

    关于自然排序:

    • Person[] 的“自然”排序将由compareTo(Person) 方法给出。
    • Student[](或ArrayList&lt;Student&gt;)的“自然”排序将由compareTo(Student) 方法给出。
    • 等等。
    • 在这些情况下都不会使用您的 compareTo(String) 方法!

    【讨论】:

      【解决方案4】:

      Person 类中的 compareTo(String) 方法没有多大意义, 因为它将thisPerson)与String进行比较。 尤其是它Person类实现的接口Comparable&lt;Person&gt;有贡献。

      您应该将thisPerson)与另一个Person进行比较:

      @Override
      public int compareTo(Person otherPerson) {
          return name.compareTo(otherPerson.name);
      }
      

      然后,在你的 ProfessorStudent 类中,你可以像这样使用上述方法:

      @Override
      public int compareTo(Person otherPerson) {
          return super.compareTo(otherPerson);
      }
      

      其实这个方法已经不需要了,因为它的行为和PersoncompareTo(Person)是一样的。 你可以省略这个方法,仍然有同样的效果。

      【讨论】:

        【解决方案5】:

        现在是用Effective Java一书第 40 条:始终如一地使用 Override 来提醒自己的好时机。

        您的基类 Person 没有在 compareTo 方法上使用 @Override 表示法,因此如果您实际上没有覆盖您的 compareTo 方法,则不会出现错误认为你是。在这种情况下,参数类型是错误的。它应该是人,而不是字符串。该方法没有被调用,而是使用默认的 on。

        -我

        【讨论】:

          【解决方案6】:

          我相信,当您想根据特定属性对 Class 进行排序时,您需要使用 Comparator。

          尝试类似:

          static final Comparator<Student> compareProgram = new Comparator<Student>() {
                  public int compare(Student e1, Student e2) {
                      //condition ( you need to return the condition)
                      return e2.program().compareTo(e1.program());
          
                  }
          };
          
          // Employee database
          static final Collection<Student> students = ... ;
          
          public static void main(String[] args) {
              List<Student> e = new ArrayList<Student>(students);
              Collections.sort(e, compareProgram);
              System.out.println(e);
          }
          

          比较器是一个存在于集合下的函数,因此您只需插入您要查找的条件。

          如果您无法实施,请告诉我。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2020-08-19
            • 2018-10-11
            • 2015-11-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多