【问题标题】:Java - how to sort object in many ways: Arrays.sort(), Comparable<T>Java - 如何以多种方式对对象进行排序:Arrays.sort()、Comparable<T>
【发布时间】:2014-11-22 20:48:29
【问题描述】:

假设我有一个包含对象的数组,其中有一些员工(对象)。他们都有:int agedouble salary。我想对这个数组进行排序,以便我的类实现Comparable &lt;Employee&gt;。我做了一个方法:

public int compareTo(Employee other) {
    return Double.compare(salary, other.salary);
}

没关系,排序工作正常。但我按double salary 排序。现在我想按int age 排序,那现在怎么办?我做了一个方法:

public int compareAge(Employee other) {
    return Integer.compare(age, other.age);
}

我该如何使用Arrays.sort()?我希望有可能同时使用这两种方法——按薪水排序,按年龄排序。谢谢你的帮助。

【问题讨论】:

    标签: java arrays sorting comparator comparable


    【解决方案1】:

    要实现对Employee 引用集合进行排序的多种方法,您应该创建实现Comparator&lt;Employee&gt; 的单独类。所以你可能有:

    public class EmployeeAgeComparator implements Comparator<Employee> {
        ...
    }
    
    public class EmployeeSalaryComparator implements Comparator<Employee> {
        ...
    }
    

    然后您只需将适当比较器的实例传递给Arrays.sort 方法。

    基本上,当有一个合理的默认排序顺序时,实现Comparable 会很好 - 但是比较器允许您将“正在比较的事物”与“进行比较的事物”分开。

    作为旁注,使用double 表示货币值(如薪水)是一个坏主意,因为二进制浮点的工作方式(例如,无法准确表示 0.1)...使用@987654327 @,或存储整数美分(或您使用的任何货币单位)。

    【讨论】:

    • 谢谢,但我无法访问 int 年龄、双倍工资的私有字段,它们是 Employee 类字段。
    • @RichardK:并且该类没有将它们作为属性公开?您可以使用匿名内部类创建一个方法来创建比较器,但使用属性会更干净 IMO。按不可观察值排序是相当奇怪的。
    • 从 Java 8 开始,将这些实现为由 lambda 表达式或 Comparator.comparing 初始化的实例通常不是更好的形式吗?
    • @Alex:是的,这很有意义。我还没有日常使用 Java 8,所以我不会首先想到 Java 8 习语。有机会会编辑。
    【解决方案2】:

    您应该使用两个Comparator 类而不是实现Comparable

    简而言之,实现Comparable 的类在单个方面与该类的实例相当。

    实现Comparator 的类将成为其他类的比较器媒介。这意味着您可以有多个比较器来比较不同方面的类。此外,Comparator 类可以传递给排序方法,例如Collections.sort()Arrays.sort(),以允许精确控制排序顺序,也可以用于控制某些数据结构的顺序,例如 sorted集合或排序的地图。

    为了达到您的目的,您可以创建两个 Comparator 类,例如:

    class SalaryComparator implements Comparator<Employee> {
        int compare(Employee a, Employee b) {
            return Double.compare(a.salary, b.salary);
        }
    }
    
    class AgeComparator  implements Comparator<Employee> {
        int compare(Employee a, Employee b) {
            return Integer.compare(a.age, b.age);
        }
    }
    

    然后在调用排序方法时传入你想使用的Comparator

    例如,如果您有一个ArrayList&lt;Employee&gt; list,并且您想按薪水对其进行排序,您可以执行以下操作:

     Collections.sort(list, new SalaryComparator()); // sort the list by salaries
    

    或者,如果您有一个 Employee[] array 并且您想按年龄对其进行排序,例如:

    Arrays.sort(array, new AgeComparator()); // sort the array by age
    

    【讨论】:

    • 这里的一个额外好处是Collections.sort() 保证是保守的。如果要按薪水排序员工,按年龄对同薪员工排序,只需先按年龄排序,再按薪水排序即可。
    • 谢谢,但我无法访问 int 年龄、双倍工资的私有字段,它们是 Employee 类字段。
    • 没问题,您应该在 Employee 类中添加像 public int getAge() { return this.age; } 这样的薪水和年龄的公共 getter 方法,然后在比较器中使用它,如 other.getAge() 而不是 other.age。薪水也一样。
    • 解决此问题的另一种方法是在 Employee 类中添加这两个比较器类,因为内部类可以访问其外部类的私有成员。
    • 谢谢,它的工作原理是这样的: public class CompareAge implements Comparator { @Override public int compare(Employee a, Employee b) { return Integer.compare(a.getAge(), b .getAge()); }
    猜你喜欢
    • 1970-01-01
    • 2018-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-16
    • 1970-01-01
    • 1970-01-01
    • 2014-04-23
    相关资源
    最近更新 更多