Comparable和Comparator比较器

引子

首先,理解什么是比较器?说白了,就是用来比较两个元素的工具,这个工具在Java中很灵活,可以自定义比较规则,你可以想怎么比较就怎么比较。1都可以小于0,0也可以大于1。当然,这些都取决于业务场景。

Comparable

Comparable,它是一个接口。这个接口中,仅仅只有一个方法,就是 compareTo() 方法。

public interface Comparable<T> {
    public int compareTo(T o);
}

Comparable 可以认为是一个内比较器,实现了 Comparable 接口的类有一个特点,就是这些类是可以和自己比较的,至于具体和另一个实现了 Comparable 接口的类如何比较,则依赖 compareTo 方法的实现,compareTo 方法也被称为自然比较方法。如果开发者add进入一个 Collection 的对象想要 Collectionssort 方法帮你自动进行排序的话,那么这个对象必须实现 Comparable 接口。compareTo 方法的返回值是 int ,有三种情况:

  • 比较者大于被比较者(也就是 compareTo 方法里面的对象),那么返回正整数;
  • 比较者等于被比较者,那么返回0;
  • 比较者小于被比较者,那么返回负整数。

 下面举个栗子:

public class RainBow implements Comparable {
  private int age;
  private String name;

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

  public int getAge() {
    return age;
  }

  public String getName() {
    return name;
  }

  @Override
  public int compareTo(Object o) {
    RainBow rainBow = (RainBow) o;
    if (this.age > rainBow.age) {
      return 1;
    } else if (this.age < rainBow.age) {
      return -1;
    } else {
      return 0;
    }

  }
}

测试:

public class TestComparable {
  public static void main(String[] args) {
    RainBow r1 = new RainBow(66, "a");
    RainBow r2 = new RainBow(77, "b");
    RainBow r3 = new RainBow(66, "c");
    RainBow r4 = new RainBow(55, "d");

    System.out.println(r1.compareTo(r2) + " " + r1.getAge() + r2.getAge());
    System.out.println(r1.compareTo(r3) + " " + r1.getAge() + r2.getAge());
    System.out.println(r2.compareTo(r4) + " " + r2.getAge() + r4.getAge());

  }
}

输出:

注意一下,前面说实现 Comparable 接口的类是可以支持和自己比较的,但是其实代码里面 Comparable 的泛型未必就一定要是自定义类,将泛型指定为 String 或者指定为其他任何任何类型都可以----只要开发者指定了具体的比较算法就行。

Comparator

Comparator,同样的,这也是一个接口。但是它的方法很多,像是一个升级版 Comparable ,其中也有一个 compare() 方法。

@FunctionalInterface
public interface Comparator<T> {
    int compare(T o1, T o2);
    //其余方法略
}

注意,这里比上面的 compareTo 多了一个 @FunctionalInterface 注解,说明,此接口可以使用 Lambda 表达式。

Comparator 可以认为是是一个外比较器,个人认为有两种情况可以使用实现 Comparator 接口的方式:

  1. 一个对象不支持自己和自己比较(没有实现 Comparable 接口),但是又想对两个对象进行比较。
  2. 一个对象实现了 Comparable 接口,但是开发者认为 compareTo 方法中的比较方式并不是自己想要的那种比较方式。

Comparator 接口里面有一个 compare 方法,方法有两个参数 T o1和 T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和 Comparable 接口一样是 int ,有三种情况:

  • o1大于o2,返回正整数;
  • o1等于o2,返回0;
  • o1小于o3,返回负整数。

再举个栗子:

实体类不改变,测试:

public class TestComparator {
  public static void main(String[] args) {
    Comparator<RainBow> comparator = (RainBow r1,RainBow r2)->{
      if (r1.compareTo(r2)>0) {
        return 1;
      } else if (r1.compareTo(r2)==0) {
        return 0;
      }else {
        return -1;
      }
    };
    RainBow r1 = new RainBow(66, "a");
    RainBow r2 = new RainBow(77, "b");
    RainBow r3 = new RainBow(66, "c");
    RainBow r4 = new RainBow(55, "d");

    System.out.println(comparator.compare(r1, r2));
    System.out.println(comparator.compare(r1, r3));
    System.out.println(comparator.compare(r3, r4));
  }
}

输出:

当然因为泛型指定死了,所以比较对象必须是同一类型的对象。

总结

总结一下,两种比较器 Comparable Comparator ,后者相比前者有如下优点:

  1. 如果实现类没有实现 Comparable 接口,又想对两个类进行比较(或者实现类实现了 Comparable 接口,但是对 compareTo 方法内的比较算法不满意),那么可以实现 Comparator 接口,自定义一个比较器,写比较算法。
  2. 实现 Comparable 接口的方式比实现 Comparator 接口的耦合性 要强一些,如果要修改比较算法,要修改 Comparable 接口的实现类,而实现 Comparator 的类是在外部进行比较的,不需要对实现类有任何修 改。从这个角度说,其实有些不太好,尤其在我们将实现类的 .class 文件打成一个 .jar 文件提供给开发者使用的时候。实际上实现 Comparator 接口的方式后面会写到就是一种典型的策略模式

当然,这不是鼓励用 Comparator ,意思是开发者还是要在具体场景下选择最合适的那种比较器而已。

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值