3

第十一章《Java实战常用类》第9节:Comparable接口和Comparator接口

 1 year ago
source link: https://blog.51cto.com/mugexuetang/5983673
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

第十一章《Java实战常用类》第9节:Comparable接口和Comparator接口

精选 原创

​对事物进行比较往往是希望对它们进行排序,因此排序的结果是由比较的结果产生的。而对事物进行比较就需要明确比较的内容是什么。例如某学校择优录取考生,就要比较所有考生的成绩,然后排列出考分的高低,而学生入学之后可能又要根据身高来排列出座位的次序。因此对两个学生进行比较,就必须先要明确到底是比较他们的考试成绩还是比较他们的身高。如果希望对两个类型相同的对象进行比较,也需要在类当中明确定义出比较规则,否则就会因没有比较规则而无法完成比较。

Comparable接口就是用于定义比较规则的接口,一个类如果实现了Comparable接口,就必须实现接口中的compareTo()抽象方法,这个方法专门用来制定比较规则,一个类如果没有实现Comparable接口,Java语言就认为这个类没有制定明确的比较规则,它的对象不能相互比较。如何在compareTo()方法中制定比较规则呢?通常情况下,程序员都是在compareTo()方法中比较两个对象的某些属性,然后根据比较结果按要求返回相应的数值。如果a对象调用自身的compareTo()方法与b对象进行比较,那么比较的语句应该是:​

a.compareTo(b);​

compareTo()方法的返回值为int型,规则要求:如果经过比较认为a比b小,那么程序员就要让compareTo()方法返回一个负数,而如果a与b相等,则返回0,如果a比b大,返回正数。compareTo()方法就是通过返回值的正负属性反映出a和b哪一个对象更大。下面的【例11_27】展示了如何对两个对象进行比较。​

【例11_27对象的比较1】

Exam11_27.java​

import java.util.Arrays;
class Stone implements Comparable{
String name;//石头的名字
double hardness;//石头的硬度
double weight;//石头的质量
public Stone(String name,double hardness,double weight){
this.name = name;
this.hardness = hardness;
this.weight = weight;
}
@Override
//比较两个石头
public int compareTo(Object o) {
Stone stone = (Stone) o;
if(this.hardness<stone.hardness){
return -1;
}else if(this.hardness==stone.hardness){
return 0;
}else{
return 1;
}
}
@Override
public String toString(){
return this.name;
}
}
public class Exam11_27 {
public static void main(String[] args) {
Stone s1 = new Stone("a石头",2.0,5.0);
Stone s2 = new Stone("b石头",1.5,8.0);
Stone s3 = new Stone("c石头",1.0,7.0);
Stone[] stones = {s1,s2,s3};
System.out.println("按照硬度比较a石头和b石头:"+s1.compareTo(s2));
Arrays.sort(stones);//按照硬度从小到达排列三块石头
System.out.print("按照硬度从小到达排列三块石头:");
System.out.println(Arrays.toString(stones));
}
}

【例11_27】中定义了两个类,其中Stone类表示石头,每个Stone类对象都有hardness和weight属性,它们分别代表石头的硬度和重量。Stone类中的compareTo()方法所定义的比较规则是比较两块石头的硬度而不是重量。在Exam11_27类的main()方法中比较了s1和s2这两块石头,并且调用sort()方法按照硬度的从小到大排列了三块石头。【例11_27】的运行结果如图11-26所示。​

第十一章《Java实战常用类》第9节:Comparable接口和Comparator接口_Comparable

图11-26【例11_27】运行结果​

从图11-26可以看出,a石头比b石头的硬度值高,所以compareTo()方法返回了一个正数,并且调用sort()方法还能对三块石头按照硬度从小到大完成排序。此处需要特别说明:如果一个类没有实现Comparable接口,那么这个类的对象所组成的数组不能调用sort()方法进行排序,否则会抛出异常,这是因为排序过程中需要对每个数组元素进行比较,没有实现Comparable接口的类不具备比较规则。​

有的时候,程序员要对某些类的对象进行比较,但这些类并没有实现Comparable接口,而程序员因为各种原因也无法修改这些类的源代码,例如程序员无法修改基础类库中的类,在这种情况下就必须借助Comparator接口完成对象的比较。Comparator接口位于java.util包,它定义了一个compare()抽象方法,这个方法从理论上来讲能够制定任何类型的两个对象的比较规则。compare()方法有两个参数,这两个参数就代表了两个被比较的对象。为方便讲述,此处把compare()方法的第一个参数称为a,而把第二个参数称为b。按照规则:当a小于b时,程序员要让compare()方法返回一个负数,而当a等于b时,compare()方法返回0,当a大于b时,compare()方法返回正数。在实际编码过程中,程序员首先要定义一个类实现Comparator接口,然后创建这个类的对象,并调用这个对象的compare()方法比较两个对象。下面的【例11_28】展示了如何使用Comparator接口比较两个对象。​

【例11_28对象的比较2】

Exam11_28.java​

import java.util.Arrays;
import java.util.Comparator;
import java.util.Objects;
class Box{
String name;//箱子的名字
double volume;//箱子的体积
public Box(String name,double volume){
this.name = name;
this.volume = volume;
}
@Override
public String toString(){
return this.name;
}
}
class BoxComparator implements Comparator<Box> {
@Override
//比较两个箱子
public int compare(Box box1, Box box2) {
if(box1.volume<box2.volume){
return -1;
}else if(box1.volume==box2.volume){
return 0;
}else{
return 1;
}
}
}
public class Exam11_28 {
public static void main(String[] args) {
Box box1 = new Box("a箱子",3.0);
Box box2 = new Box("b箱子",5.0);
Box box3 = new Box("c箱子",2.0);
Box[] boxes = {box1,box2,box3};
BoxComparator boxComparator = new BoxComparator();
System.out.print("按照体积比较a箱子和b箱子1:");
System.out.println(boxComparator.compare(box1,box2));//①
System.out.print("按照体积比较a箱子和b箱子2:");
System.out.println(Objects.compare(box1,box2,boxComparator));//②
Arrays.sort(boxes,boxComparator);//③按照体积从小到达排列三个箱子
System.out.print("按照体积从小到达排列三个箱子:");
System.out.println(Arrays.toString(boxes));
}
}

Exam11_28.java这个源文件中定义了三个类,其中Box类表示箱子,而BoxComparator类实现了Comparator接口。可以看到,BoxComparator类在实现Comparator接口时把类型参数确定为Box,这样的话BoxComparator类就成了专门比较Box类对象的比较器。在Exam11_28类的main()方法中,语句①用BoxComparator类的compare()方法比较两个Box类对象,而语句②用Objects类的compare()方法比较两个Box对象,由于Box类中本身没有定义比较对象的方法,所以还要为compare()方法传递BoxComparator类对象作为参数,这样compare()方法才能正确的完成对Box对象的比较。语句③调用Arrays类的sort()方法按照体积从小到大的方式排列了三个Box对象,也是由于Box类没有定义比较对象的方法,所以要给sort()方法传递BoxComparator类对象作为参数。【例11_28】的运行结果如图11-27所示。​

第十一章《Java实战常用类》第9节:Comparable接口和Comparator接口_Comparable_02

图11-27【例11_28】运行结果​

从图11-27可以看出:用BoxComparator类的compare()方法和用Objects类的compare()方法比较两个Box对象的效果是完全相同的,这是因为它们本质上都是用BoxComparator类中所定义的compare()方法完成了两个对象的比较过程。​

实际上,程序员通过对Comparator接口的不同实现过程还能够完成对对象的不同方式比较,例如可以定义Comparator接口的三个实现类,这三个实现类可以分别按照箱子的体积、重量、生产日期对箱子进行比较和排序,这样的话就能做到随意指定对象的比较规则。

本文字版教程还配有更详细的视频讲解,小伙伴们可以 ​点击这里观看。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK