当前位置: 首页 > 知识库问答 >
问题:

在Java中何时使用Comparator以及何时使用Comparable?

严玉泽
2023-03-14

我有一个Employee类,它有如下3个字段。

class Employee 
{
  private int empId;
  private String empName;
  private int empAge;

  public Employee(int empId, String empName, int empAge) {
    this.empId = empId;
    this.empName = empName;
    this.empAge = empAge;
}

 // setters and getters

为此,我希望根据员工姓名(empName)排序,如果多个员工的姓名相同,则根据员工id(empId)排序。

为此,我编写了一个自定义比较器,使用java.util.比较器如下所示。

   class SortByName implements Comparator<Employee> 
   {
      public int compare(Employee o1, Employee o2) {
       int result = o1.getName().compareTo(o2.getName());
      if (0 == result) {
        return o1.getEmpId()-o2.getEmpId();
    } else {
        return result;
    }
   }
  }

我已经创建了8个Employee对象并添加到ArrayList中,如下所示。

    List<Employee> empList = new ArrayList<Employee>();

    empList.add(new Employee(3, "Viktor", 28));
    empList.add(new Employee(5, "Viktor", 28));
    empList.add(new Employee(1, "Mike", 19));
    empList.add(new Employee(7, "Mike", 19));
    empList.add(new Employee(4, "Mark", 34));
    empList.add(new Employee(6, "Jay", 34));
    empList.add(new Employee(8, "Gayle", 10));
    empList.add(new Employee(2, "Gayle", 10));          

并使用上述比较器对列表进行如下排序。

Collections.sort(empList,new SortByName());

它工作得非常好。但这可以使用类似的方法来完成,如下所示。

class Employee implements Comparable<Employee> {
private int empId;
private String name;
private int age;

public Employee(int empId, String name, int age) {
    this.empId = empId;
    this.name = name;
    this.age = age;
}

//setters and getters

@Override
public int compareTo(Employee o) {
    int result = this.getName().compareTo(o.getName());
    if (0 == result) {
        return this.getEmpId()-o.getEmpId();
    } else {
        return result;
    }

}

}

使用Collections.sort(empList)对列表进行排序;

所以我想知道用例是什么,或者我们在哪里使用这两者?我知道Compariable用于自然排序,只能使用一个字段进行排序,Compariator用于多字段排序。但是,如果我们看到我的示例,那么这两个接口都可以同时执行这两个操作。因此,请解释一下这两种方法的独特之处,其中另一种方法无法使用。

共有3个答案

谭昕
2023-03-14

有些类根据其性质指定了顺序(例如,字典顺序是事实上的标准)或日期。对于这些类,可以通过实现Compariable来定义它们的自然顺序

好的,让我们看另一个例子。假设你有一个你提到的员工列表,你想做一些其他的事情。例如:您希望能够灵活地按姓名、收入、出生日期或。。。(假设您想选择如何订购它们)。对于这种情况,您可能需要指定要使用的精确比较器,具体取决于您选择排序的行。

另一个示例:Employee类已经存在,并且确实指定了一些订单,但是您对这个订单不满意。现在,您只需使用比较器指定自己的顺序,即可获得所需的行为。

公孙宏远
2023-03-14

如果你真的想知道两者的独特之处。

实现Compariable可以将您的类与其他类进行比较。

Employee implements Comparable<Integer>

比较器是一种比较相同类类型的两个实例的算法。

拓拔俊艾
2023-03-14

使用Compariable如果要定义所讨论对象的默认(自然)排序行为,通常的做法是使用技术或自然(数据库?)此对象的标识符。

如果要定义外部可控排序行为,请使用比较器,这可以覆盖默认排序行为。您可以定义任意数量的排序行为,您可以根据需要使用这些行为。

 类似资料:
  • 我和我的团队一直在使用Spring boot开发一系列微服务。由于服务经历了JUnit和Spring Boot升级(我们现在使用的是Spring Boot 2和JUnit 5),不同开发人员实现的不同JUnit现在使用不同的模式: @扩展为 今天,它们之间的区别是什么?我们真的需要它们来进行单元测试还是嵌入到一些新的Spring Boot注释中?

  • 问题内容: 在哪种情况下,您应该使用原始类型()还是引用类型()? 问题答案: 在哪种情况下,您应该使用原始类型()还是引用类型()? 根据经验,除非必须使用包装原始语言的类,否则我将使用原始语言(例如)。 一种情况是必须使用包装器类,例如在使用泛型的情况下,因为Java不支持将原始类型用作类型参数: 而且,在许多情况下,我将利用autoboxing和unboxing的优势,因此不必显式执行从原语

  • 问题内容: 我正在从OracleDocGenericMethod中阅读有关泛型方法的信息。当比较指出何时使用通配符以及何时使用通用方法时,我对此感到非常困惑。引用文档。 我们可以在这里使用通用方法: […]这告诉我们类型参数正在用于多态。它的唯一作用是允许在不同的调用站点使用各种实际的参数类型。在这种情况下,应使用通配符。通配符旨在支持灵活的子类型化,这就是我们在此要表达的内容。 我们难道不认为像

  • 问题内容: 在大多数情况下,我将使用异常来检查代码中的条件,我想知道何时才是使用断言的适当时间? 例如, 您能指出断言如何适合这里吗?我应该使用断言吗? 似乎我从未在生产代码中使用断言,而仅在单元测试中看到断言。我确实知道,在大多数情况下,我可以像上面一样使用异常来进行检查,但是我想知道“专业”地执行异常的适当方法。 问题答案: 断言应用于检查不应发生的事情,而异常应用于检查可能发生的事情。 例如

  • 我试图理解Docker Compose和Docker Swarm之间的区别或相似之处。 通过阅读留档,我明白docker-compose提供了一种将不同容器绑定在一起并协同工作的机制,作为一个单一的服务(我猜它使用的功能与用于链接两个容器的--link命令相同) 此外,我对docker-swarm的理解是,它允许您管理不同docker主机的集群,每个主机都运行一些docker-image的几个容器

  • 我不知道如何正确使用比较器接口。 注意:我不想使用我在大多数代码中看到的“一行”比较器实现,这意味着: 再说一遍,我不想使用这个,因为我将对许多不同的ArrayList进行排序,每次这样做似乎都是浪费空间。我想以某种方式让它工作,让我的compareTo方法在一个地方编写一次。 我尝试了许多不同的方法,但我对实现接口还不熟悉,所以我可能遗漏了一些东西。 这是我的Card类和它的比较方法。(注意:让