概述:
可比接口:
- 创建一个实现Comparable接口的类
比较器界面:
- 创建一个实现Comparator接口的类
- 通过匿名类实现Comparator接口
- 使用比较器辅助方法
为什么在Java中使用Comparable或Comparator:排序
有几种在Java中对对象集合进行排序的方法
第一个方法是使用内置的排序方法对Java原语和包装器类的集合/数组进行排序
- Array.sort(unsortedArray):返回类型为void,未排序的数组按原位排序
- Collections.sort(unsortedArrayList):返回类型为空,未排序的列表按原位排序
对于Java primite或wrapper类,内置方法可以直接使用。
对于自定义对象,为了使静态排序方法起作用,这些对象应该是实现Comparable接口的类的实例。
如果您尝试在未实现Comparable接口的对象的数组或对象列表上使用Arrays.sort或Collections.sort,则会收到以下运行时异常
| Error:
| no suitable method found for sort ( java . util . ArrayList < Employee >)
| method java . util . Collections .< T > sort ( java . util . List < T >) is not applicable
| ( inference variable T has incompatible bounds
| equality constraints: Employee
| lower bounds: java . lang . Comparable <? super T >)
| method java . util . Collections .< T > sort ( java . util . List < T >, java . util . Comparator <? super T >) is not applicable
| ( cannot infer type - variable ( s ) T
| ( actual and formal argument lists differ in length ))
| Collections . sort ( Employees );
| ^--------------^
可比的界面
- 要在自定义类上使用Arrays和Collections内置的排序方法,请实现Comparable接口
- 任何实现此接口的类都必须提供compareTo(T obj)方法的实现细节。 此方法返回负数(如果'this'是<),0或正数(如果'this'是>)
- 可比对象提供了一种默认的对象排序方式,并且无法进行动态更改
public class Employee implements Comparable < Employee > {
private int id ;
public Employee ( int id ){
this . id = id ;
}
public int getId (){
return id ;
}
//*****************
@Override
public int compareTo ( Employee emp ){
return ( this . id - emp . id )
}
//*****************
}
比较器界面
- 这样,我们可以定义不同的实现,以便对不同类的两个实例进行排序
- 使用比较器是将两个实例映射到具有唯一默认方式的Comparable接口时以不同方式对两个实例进行排序的方式
- 任何实现此接口的类都必须实现compare(Object o1,Object o2)方法
- 您实现比较器以定义自己的实例排序方式
要使用Comparator接口对Java中的对象数组或对象列表进行排序,您需要从实现Collection接口的类型的实现开始:
列表(界面)
- 数组列表
- 向量
- 堆
- 链表
设置(界面)
- 哈希集
- 链接哈希集
SortedSet(接口)
- 树集
队列(接口)
- PriorityQueue
出队(接口)
- ArrayDeque
地图(界面)
- 哈希图
SortedMap(接口)
- 树状图
提示:比较器(分配给变量的匿名类或实现比较器接口的类)可以传递给sort方法
- Collections.sort(..接受比较器作为参数)
- Arrays.sort(..接受比较器作为参数)
通过匿名类实现比较器
使用匿名类创建Comparator的实例并将其分配给变量。 在这个匿名类中实现compare方法
public static Comparator < Employee > grade1Emlpyees = new Comparator < Employee > {
@Override
public int compare ( Employee e1 , Employee e2 ) {
return ( int ) ( e1 . getRank () - e2 . getRank ());
}
}
- 您只需创建比较器并将其传递给Arrays和Collections的sort方法,就可以对对象列表(也包括不同类的实例)进行排序
- 如果对象已实现Comparable接口的compareTo方法,则可以使用Comparator覆盖此方法,该方法将覆盖可比较的接口实现。 完成此操作后,可以将数组和集合的排序方法与新创建的比较器一起使用
// Create class
public class Employee {
private int age ;
private String name ;
private double salary ;
public Employee ( int age , String name , double salary ) {
this . age = age ;
this . name = name ;
this . salary = salary ;
}
public int getAge (){ return this . age ;}
public String getName () { return this . name ;}
public double getSalary () { return this . salary ;}
}
// Create Comparator with an Anonymous class
public Comparator < Employee > compareByAge = new Comparator < Employee >(){
@Override
public int compare ( Employee e1 , Employee e2 ){
return e1 . getAge () - e2 . getAge ();
}
}
//Create the lists
Employee e1 = new Employee ( 10 , "Employee1" , 100.00 );
Employee e2 = new Employee ( 12 , "Employee2" , 100.00 );
Employee e3 = new Employee ( 11 , "Employee3" , 100.00 );
ArrayList < Employee > employeeCollection = new ArrayList <>( List . of ( e1 , e2 , e3 ));
Employee [] employeeArray = { e1 , e2 , e3 };
// User Array sort and Collection sort
Collections . sort ( employeeCollection , compareByAge );
Arrays . sort ( employeeArray , compareByAge );
//After
for ( Employee e: employeeCollection ) {
System . out . println ( e . getAge ());
}
for ( Employee e: employeeArray ) {
System . out . println ( e . getAge () + " " + e . getName () + " " + e . getSalary ());
}
比较器类的实现
您可以通过创建类并扩展比较器来实现比较器
public class EmployeeComparatorByAge implements Comparator < Employee > {
@Override
public int compare ( Employee e1 , Employee e2 ) {
return e1 . getAge () - e2 . getAge ();
}
}
//use the new keyword to create an instance of the comparator withouth parameters (uses default initializer = empty one)
Collections . sort ( employeeCollection , new EmployeeComparatorByAge ());
Arrays . sort ( employeeArray , new EmployeeComparatorByAge ());
用于创建比较器的比较器实用程序方法
如果对象未实现可比较的接口,则可以使用Comparator实用程序方法来创建Comparators以便对字段进行排序,链比较器或反向排序
小费:
- 如果您在Pojo中实现了compareTo或compare,则可以使用sort方法
- 否则,您可以通过将比较器传递给sort方法来对集合进行排序
创建一个POJO
public class Locations implements Comparator < Locations > {
private double longitude ;
private double latitude ;
private UUID uuid ;
private Date date ;
public Locations ( double longitude , double latitude ) {
this . longitude = longitude ;
this . latitude = latitude ;
this . uuid = UUID . randomUUID ();
this . date = new Date ();
}
public double getLongitude () {
return longitude ;
}
public double getLatitude () {
return latitude ;
}
@Override
public int compare ( Locations o1 , Locations o2 ) {
return 0 ;
}
}
使用比较器实用程序方法
- 比较=>返回一个比较器
- thenComparing(用于链接比较器)=>返回用于链接的比较器
Comparator sortByLongitude = Comparator . comparing ( Locations: : getLongitude ()); // => this returns a Comparator that can be used in Collections.sort
Collections . sort ( listOfLocationObjects , sortByLongitude );
Comparator groupSort = Comparator . comparing ( Locations: : getLongitude ). thenComparing ( Locations: : getDate ()). thenComparing ( Locations: : getId ()); //=> sort first by longitude, then by date and then finalize with a sort by ID;
Collections . sort ( listOgObjects , groupSort );
//Reverse order
Comparator groupSortReversed = Comparator . comparing ( Locations: : getLongitude ). reversed ();
Collections . sort ( listOgObjects , groupSortReversed );
From: https://dev.to/micosmin/understanding-comparable-and-comparator-3l0i