java中Comparable和Comparator两种比较器的区别
Comparable和Comparator接口都是为了对类进行比较,众所周知,诸如Integer,double等基本数据类型,java可以对他们进行比较,而对于类的比较,需要人工定义比较用到的字段比较逻辑。可以把Comparable理解为内部比较器,而Comparator是外部比较器,基本的写法如下:
class Apple implements Comparable<Apple>{ int id; double price; public Apple(int id, double price) { this.id = id; this.price = price; } public int compareTo(Apple o) { //return Double.compare(this.getPrice(),o.getPrice()); if (Math.abs(this.price-o.price)<0.001) return 0; else return (o.price-this.price)>0?1:-1; } @Override public String toString() { return "Apple{" + "id=" + id + ", price=" + price + '}'; } }
class AESComparator implements Comparator<Apple>{ public int compare(Apple o1, Apple o2) { if (Math.abs(o1.price-o2.price)<0.001) return 0; else{ return (o1.price-o2.price)>0?1:-1; } } }
实现了Comparable接口的类需要实现compareTo()方法,传入一个外部参数进行比对,实现了Comparator接口的方法需要实现compare()方法,对外部传入的两个类进行比较,从而让外部方法在比较时调用。
两者的区别是实现Comparator接口代码更加灵活,可以定义某个类的多个比较器,从而在排序时根据实际场景自由调用,而Comparable接口实现后便不能改动。两种接口的调用方式如下:
class AESComparator implements Comparator<Apple>{ public int compare(Apple o1, Apple o2) { if (Math.abs(o1.price-o2.price)<0.001) return 0; else{ return (o1.price-o2.price)>0?1:-1; } } } class DESComparator implements Comparator<Apple>{ public int compare(Apple o1, Apple o2) { if (Math.abs(o1.price-o2.price)<0.001) return 0; else { return (o1.price-o2.price)>0?-1:1; } } }
public static void main(String[] args) { Apple apple1 = new Apple(1,4.8); Apple apple2 = new Apple(2,5.9); Apple apple3 = new Apple(3,8.5); List<Apple> list = new ArrayList<Apple>(); list.add(apple1); list.add(apple3); list.add(apple2); System.out.println("Comparable=========="); System.out.printf("this list of apples: %s\n",list); Collections.sort(list); System.out.printf("this list of apples: %s\n",list); System.out.println("Comparator=========="); System.out.printf("this list of apples: %s\n",list); Collections.sort(list,new DESComparator()); System.out.printf("this list of apples: %s\n",list); Collections.sort(list,new AESComparator()); System.out.printf("this list of apples: %s\n",list); } }
上述代码存在的问题,不能在比较器中进行double类型的减法操作,因为对于值比较大的double,减法操作容易导致值的溢出,java7对每一种包装类型的比较新增了compare()方法,改造后的代码如下:
class Apple implements Comparable<Apple>{ int id; double price; public Apple(int id, double price) { this.id = id; this.price = price; } public int compareTo(Apple o) { return Double.compare(this.price,o.price); } @Override public String toString() { return "Apple{" + "id=" + id + ", price=" + price + '}'; } } class AESComparator implements Comparator<Apple>{ public int compare(Apple o1, Apple o2) { return Double.compare(o1.price,o2.price); } } class DESComparator implements Comparator<Apple>{ public int compare(Apple o1, Apple o2) { return Double.compare(o2.price,o1.price); } }
查看Double.compare的源码如下
public static int compare(double d1, double d2) { if (d1 < d2) return -1; // Neither val is NaN, thisVal is smaller if (d1 > d2) return 1; // Neither val is NaN, thisVal is larger // Cannot use doubleToRawLongBits because of possibility of NaNs. long thisBits = Double.doubleToLongBits(d1); long anotherBits = Double.doubleToLongBits(d2); return (thisBits == anotherBits ? 0 : // Values are equal (thisBits < anotherBits ? -1 : // (-0.0, 0.0) or (!NaN, NaN) 1)); // (0.0, -0.0) or (NaN, !NaN) }