了解可比和比较器

概述:

可比接口:

  • 创建一个实现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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值