Java常用类之比较器的使用详解

发布时间:

Java 中的对象,正常情况下,只能进行 = 或 != 比较。不能使用 > 或 < 的比较,但是在开发场景中,我们需要对多个对象进行排序,这就需要比较对象的大小。此时我们如何实现呢?java为我们提供了两个接口,使用两个接口中的任何一个: Comparable 或 Comparator 即可实现对象的比较大小!

java 比较器概述

在 Java 中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。

Java 实现对象排序的方式有两种:

  • 自然排序: java. lang.Comparable
  • 定制排序: java.util.Comparator

自然排序 Comparable

1.Comparable 接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。

2.实现 Comparable 的类必须实现 compareTo (Object obj)方法,两个对象即通过 compareTo (Object obj)方法的返回值来比较大小。如果当前对象 this 大于形参对象 obj ,则返回正整数,如果当前对象 this 小于形参对象 obj ,则返回负整数,如果当前对象 this 等于形参对象 obj ,则返回零。

3.实现 Comparable 接口的对象数组可以通过 Collections.sort 或Arrays.sort 进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

注:像 String 、包装类等实现了 Comparable 接口,重写了 compareTo(obj) 方法,进行了从小到大的排列!

案例一:对字符串数组进行排序

import java.util.Arrays;

public class ComparableTest {
public static void main(String[] args) {
String[] arr = new String[]{"aniu","tom","tony","lisa"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
}

Java常用类之比较器的使用详解

这是因为我们的String实现了Comparable接口,并对compareTo方法进行了重写!

Java常用类之比较器的使用详解

案例二:对自定义对象进行排序

此时我们要将这个对象实现Comparable接口,然后重写compareTo方法。

package 比较器;

import java.util.Arrays;

public class ComparableDemo {
public static void main(String[] args) {
Books[] book = new Books[4];
book[0] = new Books("The Beautiful and the Damned",68);
book[1] = new Books("Where Angels Fear to Tread",45);
book[2] = new Books("These Lovers Fled Away",35);
book[3] = new Books("The Left Hand of Darkness",58);

Arrays.sort(book);
for(Books item:book){
System.out.println(item.toString());
}
//System.out.println(Arrays.toString(book));
}
}

class Books implements Comparable{
String name;
double price;
public Books(String name, double price) {
this.name = name;
this.price = price;
}
//重写compareTo
@Override
public int compareTo(Object o) {
//按照图书价格从小到大排序
if (o instanceof Books){
Books b = (Books) o;
if(this.price>b.price){
return 1;
}else if(this.price<b.price) {
return -1;
}else{
return 0;
}
}
throw new RuntimeException("传入的数据类型不一致!");
}
//重写 toString
@Override
public String toString() {
return "Books{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}

Java常用类之比较器的使用详解

这样写是从小到大排,如果要从大到小排,则需要将return值反过来!

定制排序 Comparator

1.当元素的类型没有实现 java.lang.Comparable 接口而又不方便修改代码,或者实现了 java.lang.Comparable 接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排序的比较。

2.重写 compare(Object o1,Object o2) 方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。

3.可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort ),从而允许在排序顺序上实现精确控制。

4.还可以使用 Comparator 来控制某些数据结构(如有序 set 或有序映射)的顺序,或者为那些没有自然顺序的对象 colection 提供排序。

案例:对自定义对象进行排序

package 比较器;

import java.util.Arrays;
import java.util.Comparator;

public class ComparatorDemo {
public static void main(String[] args) {
Book[] book = new Book[4];
book[0] = new Book("The Beautiful and the Damned",68);
book[1] = new Book("Where Angels Fear to Tread",45);
book[2] = new Book("These Lovers Fled Away",35);
book[3] = new Book("The Left Hand of Darkness",58);

Arrays.sort(book, new Comparator(){
//按照价格从大到小排
@Override
public int compare(Object o1, Object o2) {
if(o1 instanceof Book && o2 instanceof Book){
Book b1 = (Book)o1;
Book b2 = (Book)o2;
return -Double.compare(b1.price,b2.price); //这里我们直接调用Double的compare方法
}
throw new RuntimeException("传入的数据类型不一致!");
}
});
for(Book item:book){
System.out.println(item.toString());
}
//System.out.println(Arrays.toString(book));
}
}

class Book{
String name;
double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
//重写 toString
@Override
public String toString() {
return "Book{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}

Java常用类之比较器的使用详解

可以从代码看到,这里这里我们直接调用Double的compare方法进行了比较,不用像上面的案例一样手写了,当然我们也可以用comparTo方法,因为上面提到了,包装类也实现了Comparable接口,但Double重写的comparTo方法底层依旧是compare方法!因为是从大到小排,所以在Double前加个负号!

Comparable 与 Comparator 的使用对比

Comparable 接口的方式一旦一定,保证 Comparable 接口实现类的对象在任何位置都可以比较大小 ,而 Comparator 接口属于临时性的比较。再者一个很直观的是Comparable是在自定义类中将比较规则在类中写死了的,而Comparator则比较灵活,在比较时定义比较规则,看起来灵活一点!