java中Comparable和Comparator两种比较器的区别

Python069

java中Comparable和Comparator两种比较器的区别,第1张

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)

}

内部比较器实现Comparable和外部比较器实现Comparator

在剑指offer上遇到了一题,使用外部比较器到Comparator

一)Comparable

Comparable 是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”。假设现在存在“实现Comparable接口的类的对象的List列表(或数组)”,则该List列表(或数组)可以通过 Collections.sort(或 Arrays.sort)进行排序。

Comparable定义:

说明实现该接口的类必须实现该方法,对象就可以比较大小。假设我们通过 x.compareTo(y) 来“比较x和y的大小”。若返回“负数”,意味着“x比y小”;返回“零”,意味着“x等于y”;返回“正数”,意味着“x大于y”。

Java的一些常用类已经实现了Comparable接口,并提供了比较大小的标准。包装类:按照它们对应的数值大小进行比较。Character,Boolean,String,Date,Time等也都实现了Comparable接口。

(二)Comparator

我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。

Comparator接口的源码如下:

若一个类要实现Comparator接口:它一定要实现compare(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。因为Object类是所有类的父类,也就是说实现接口的子类已经重写了equals方法。

int compare(T o1, T o2) 是“比较o1和o2的大小”。返回“负数”,意味着“o1比o2小”;返回“零”,意味着“o1等于o2”;返回“正数”,意味着“o1大于o2”。

然后复习了一下

为什么实现了equals()就必须实现hashCode()?

每次看都有新发现,可能是以前就不是很懂的原因

我们使用覆写equals是为了满足我们的需求,取代它原来的作用,为了单纯地比较它们内容而不比较地址,但是hashcode阻止了我们。所以我们要把hashcode一并覆写。让equals方法和hashCode方法始终在逻辑上保持一致性。

hashCode方法是将对象的存储地址进行映射

“设计hashCode()时最重要的原则就是:无论什么时候,对同一个对象调用hashCode()都应该产生同样的值。如果在将一个对象用put()添加进HashMap时产生一个hashCode值,而用get()取出时却产生了另一个hashCode值,那么就无法获取该对象了。所以如果你的hashCode方法依赖于对象中易变的数据,你就要小心了,因为此数据发生变化时,hashCode()方法就会生成一个不同的散列码”。

一般来说,如果你要把一个类的对象放入容器中,那么通常要为其重写equals()方法,让他们比较地址值而不是内容值。特别地,如果要把你的类的对象放入散列中,那么还要重写hashCode()方法;要放到有序容器中,还要重写compareTo()方法。

method <some method>in java.util.Comparator,答案要求是java.util.comparator

equals 是java.lang.string的

compareTo是是java.lang.Comparable的

compare(Object o1,Object o2)方法是java.util.Comparator<T>接口的方法

所以选E