目录
Comparable比较器和Camparator比较器的区别
为什么需要比较器
对于基本数据类型,可以使用:
- ==
- !=
- >
- <
来比较两个基本数据类型的大小关系,得到的结论可以是
- 相等
- 不相等
- 大于
- 小于
中间的任何一个。这四个运算符的存在,足够支持开发者进行排序操作了。
但是,如果是两个对象的内容进行比较呢?
首先比较的是内容,肯定不能使用上面的四个运算符,因为两个对象使用运算符进行运算时,比较的是两个对象在堆中的地址而不是两个对象的具体内容,因此使用上面四个运算符是必然无法进行两个对象内容的比较的。
此时,在java中便存在一个比较器,可以使用比较器对两个对象进行排序,从而对对象内容的关系进行判断(大于、小于、等于)。
存在了比较器之后,便可以直接调用比较器对内容进行判断,从而可以很方便的实现多个对象的排序。
在java中,提供了两种比较器:
- Comparable比较器,存在于java.lang软件包中,进行的是两个对象内容之间的自然排序,即只能对对象进行单纯的升序排序和降序排序。
- Camparator比较器,存在于java.util软件包中,这个比较器允许进行自定义排序。(例如对对象的某一个关键字进行升序排序,而当这个关键字的值相同时,再根据另一个关键字进行降序排序)。
Comparable比较器
在Comparable接口中,只有一个抽象方法:
既然比较器比较的是两个对象内容的大小关系,那么此时便可以随便找一个引用数据类型观察一下其对compareTo方法的重写,此处以String类为例:
阅读完该方法的描述后,可以知道:
- 该方法只有一个形参,名为anotherString,表示需要和当前字符串进行比较的字符串。
- 该方法的返回值有三种:大于零的整数、小于零的整数、0。
- 在对字符串进行比较时,每次比较的是两个字符串对应位置(描述为第k个位置)的Unicode编码值,并且是使用当前字符串第k个位置字符的Unicode编码值减去anotherString字符串第k个位置字符Unicode编码值,因此会得到一个整数,这个整数只会存在三种情况:大于零、小于零、等于零,正好对应了该方法的三种返回值。
- 若是两个字符串的长度不相等,那么便返回当前字符串和anotherString字符串长度的差值,即当前字符串的长度减去anotherString字符串的长度,同样会得到一个整数,这个整数同样也只会存在三种情况:大于零、小于零、等于零,正好对应了该方法的三种返回值。
由此看来,使用compareTo(String)方法是可以得到两个字符串的大小关系。
下面便来测试一下:
public class Test {
public static void main(String[] args) {
String str1 = "1234abcd";
String str2 = "1234abcd";
String str3 = "1234ab";
System.out.println("str1 compare str2 = " + str1.compareTo(str2));
System.out.println("str1 compare str3 = " + str1.compareTo(str3));
System.out.println("str2 compare str3 = " + str2.compareTo(str3));
System.out.println("str3 compare str2 = " + str3.compareTo(str2));
}
}
得到的结果为:
可以看到,和之前分析的结果一致,当两个串相等时,返回0;当当前字符串的长度和形参字符串的长度不相等时,返回的是当前字符串的长度和形参字符串长度之差,即this.length()-anotherString.length()。
上面的compareTo()方法是在已有的类中已经重写好的,如果在自己定义的类中,实现compareTo()比较器,那该如何实现呢?
下面来看一个栗子:
public class class1 implements Comparable<class1> {
private int num1;
public void setNum1(int num1) {
this.num1 = num1;
}
/**
* 如果当前对象的num1值大于比较对象的num1值,返回一个正数;
* <p>
* 如果当前对象的num1值小于比较对象的num1值,返回一个负数;
* <p>
* 如果当前对象的num1值等于比较对象的num1值,返回一个0;
*
* 那么,在排序中,返回值为正数则表示降序排序;返回值为负数则表示升序排序
**/
@Override
public int compareTo(class1 o) {
return this.num1 - o.num1;
}
}
在class1类中,实现了compareTo比较器。
下面对这个比较器进行测试:
public class Test {
public static void main(String[] args) {
class1 c1 = new class1();
class1 c2 = new class1();
c1.setNum1(1);
c2.setNum1(2);
System.out.println(c1.compareTo(c2));
System.out.println(c2.compareTo(c1));
}
}
测试结果为:
可以看到,当对象c1和对象c2使用比较器进行比较时,返回了一个负值,表示对象c1是小于对象c2的;当对象c2和对象c1使用比较器进行比较时,返回了一个正值,表示对象c2是大于对象c1的。
Camparator比较器
可以看到,Camparable比较器只能对两个对象中的单一关键字进行比较,但在现实中,还存在许多需要对多个关键字进行比较的场合,此时便可以使用Camparator比较器进行多关键字比较,或者说是自定义排序规则的比较。
既然是自定义排序规则,那么便需要对已有的排序规则进行重写。
下面来看一个自定义排序的栗子:
有一个名为Goods的类,类中含有构造器,set和get方法以及重写了一个toString()方法
public class Goods {
private String GoodsName;
private int GoodPrice;
public Goods() {
}
public Goods(String name, int price) {
this.GoodPrice = price;
this.GoodsName = name;
}
public String getGoodsName() {
return GoodsName;
}
public void setGoodsName(String goodsName) {
GoodsName = goodsName;
}
public int getGoodPrice() {
return GoodPrice;
}
public void setGoodPrice(int goodPrice) {
GoodPrice = goodPrice;
}
@Override
public String toString() {
return "Goods{" +
"GoodsName='" + GoodsName + '\'' +
", GoodPrice=" + GoodPrice +
'}' + '\n';
}
}
下面对这个类的对象进行排序:
import java.util.Arrays;
import java.util.Comparator;
public class Test {
public static void main(String[] args) {
Goods[] goods = {new Goods("bread", 6), new Goods("milk", 2), new Goods("cola", 3), new Goods("bread", 15)};
//按照名称进行升序排序,如果名称相同,则按照价格进行降序排序
Arrays.sort(goods, new Comparator<Goods>() {
@Override
public int compare(Goods o1, Goods o2) {
if (o1.getGoodsName().equals(o2.getGoodsName())) {
return o2.getGoodPrice() - o1.getGoodPrice();
} else {
return o1.getGoodsName().compareTo(o2.getGoodsName());
}
}
});
System.out.println(Arrays.toString(goods));
}
}
可以看到,此时重写了Arrays类的sort()方法,实现了Comparator接口中的compare方法,该方法的效果是:按照名称对goods对象中的数据进行升序排序,如果名称相同,那么便对goods对象中名称相同的数据进行降序排序。
程序的运行结果为:
Comparable比较器和Camparator比较器的区别
Comparable比较器只能比较仅含有单个关键字的对象,因此仅适用于对单个关键字进行排序,而Camparator比较器作为Comparable比较器性能不足的弥补,可以允许自定义比较规则,因而可以用于多个关键字的排序。
两个比较器结合使用可以十分灵活地进行对象的排序。