一、比较器
在 Java 中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。
Java 实现对象排序的方式有两种:
自然排序: java.lang.Comparable
定制排序: java.util.Comparator
二、自然排序:java.lang.Comparable
1、概述
Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。 如果当前对象this大于形参对象obj, 则返回正整数,如果当前对象this小于形参对象obj, 则返回负整数,如果当前对象this等于形参对象obj, 则返回零。
实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或Arrays.sort进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。
对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals一致。 建议(虽然不是必需的) 最好使自然排序与 equals 一致。
2、典型实现
Compareable 的典型实现:(默认都是从小到大排列的)
-
- String:按照字符串中字符的Unicode值进行比较;
- Character:按照字符的Unicode值来进行比较;
- Boolean: true 对应的包装类实例大于 false 对应的包装类实例;
- Date、 Time等:后面的日期时间比前面的日期时间大;
- 数值类型对应的包装类以及BigInteger、 BigDecimal:按照它们对应的数值大小进行比较;
- String:按照字符串中字符的Unicode值进行比较;
3、案例
Goods 商品类:
1 public class Goods implements Comparable{
2
3 private String name;
4 private double price;
5
6 public Goods() {
7 }
8
9 public Goods(String name, double price) {
10 this.name = name;
11 this.price = price;
12 }
13
14 public String getName() {
15 return name;
16 }
17
18 public void setName(String name) {
19 this.name = name;
20 }
21
22 public double getPrice() {
23 return price;
24 }
25
26 public void setPrice(double price) {
27 this.price = price;
28 }
29
30 @Override
31 public String toString() {
32 return "Goods{" +
33 "name='" + name + '\'' +
34 ", price=" + price +
35 '}';
36 }
37
38 //指明商品比较大小的方式:按照价格从低到高排序,再按照产品名称从高到低排序
39 @Override
40 public int compareTo(Object o) {
41 if(o instanceof Goods){
42 Goods goods = (Goods)o;
43 //方式一:
44 if(this.price > goods.price){
45 return 1;
46 }else if(this.price < goods.price){
47 return -1;
48 }else{
49 //return 0;
50 return -this.name.compareTo(goods.name);
51 }
52 //方式二:
53 //return Double.compare(this.price,goods.price);
54 }
55 throw new RuntimeException("传入的数据类型不一致!");
56 }
57 }
测试类:
1 public class ComparableTest {
2 public static void main(String[] args) {
3 Goods[] all = new Goods[4];
4 all[0] = new Goods("《红楼梦》 ", 100);
5 all[1] = new Goods("《西游记》 ", 80);
6 all[2] = new Goods("《三国演义》 ", 140);
7 all[3] = new Goods("《水浒传》 ", 120);
8 Arrays.sort(all);
9 System.out.println(Arrays.toString(all));
10 }
11 }
三、定制排序:java.util.Comparator
1、概述
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序, 强行对多个对象进行整体排序的比较。
重写compare(Object o1,Object o2)方法,比较o1和o2的大小: 如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示
o1小于o2。
可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。
还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。
2、方法说明
java.util.Comparator<T>接口:
抽象方法:int compare(T o1, T o2)
<T> 是泛型,可以理解成 Object。
java.util.Comparator接口:
抽象方法:int compare(Object o1, Object o2)
说明:这个接口是代表 Java 中比较两个对象的大小标准。而且是一种“定制”比较的标准。
这个接口中没有规定如何比较两个对象的大小。
但是规定了:如果认为 o1 大于 o2,那么就返回正整数表示;
如果认为 o1 小于 o2,那么就返回负整数表示;
如果认为 o1 等于 o2,那么就返回0表示;
3、案例
Demo:定制排序(自定义排序)
1 @Test
2 public void test() {
3 Goods[] all = new Goods[4];
4 all[0] = new Goods("War and Peace", 100);
5 all[1] = new Goods("Childhood", 80);
6 all[2] = new Goods("Scarlet and Black", 140);
7 all[3] = new Goods("Notre Dame de Paris", 120);
8 Arrays.sort(all, new Comparator() {
9 @Override
10 public int compare(Object o1, Object o2) {
11 Goods g1 = (Goods) o1;
12 Goods g2 = (Goods) o2;
13 return g1.getName().compareTo(g2.getName());
14 }
15 });
16 System.out.println(Arrays.toString(all));
17 }
总结:
Arrays 的 sort 方法有两种:
(1)void sort(Object[] arr)
根据元素的自然顺序对指定对象数组按升序进行排序,数组中的所有元素必须实现 Comparable 接口。
(2)void sort(Object[] arr, Comparator c)
根据“指定比较器”产生的顺序对指定对象数组进行排序,数组中的所有元素都必须是通过“指定比较器”可相互比较的。