前言
在Java中,如Integer、Double等基本数据类型之间可以直接进行比较大小,而Java是一门面向对象语言,一组对象之间进行排序比较显得尤为重要,那对象之间又该如何进行比较呢?
Comparable与Comparator都是Java提供的对象间进行比较的接口,只不过用法上会有差异。
本质是根据类中的属性进行排序,这里的属性通常指基本数据类型,当然也可以是引入数据类型,如String、自定义类,在这里自定义类比较的也是类中的属性。
Comparable接口
使用Comparable给对象进行排序,目标对象只需要实现接口并重写comparTo方法即可。
其中Comparable接口需要传入泛型,一般传入本类,也可以不传或传入Object,再重写方法的时候进行instanceof判断进行强转即可。
public class ComparableTest implements Comparable<ComparableTest>{
//两个基本属性
private Integer id;
private String name;
public ComparableTest(Integer id, String name) {
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "ComparableTest{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
//重写的compareTo方法
@Override
//传入的参数时与this比较的对象
public int compareTo(ComparableTest o) {
//先进行id属性的比较,如果this大返回1表示升序排列,相反返回-1表示降序。
if (this.id > o.id) {
return 1;
}else if (this.id < o.id) {
return -1;
}
//如果id属性值相等,那么就根据第二个属性String进行比较
else {
//这里直接返回是因为String类已经实现的Comparable接口
return this.name.compareTo(o.name);
}
}
}
String类实现的comparTo方法
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
测试
public static void main(String[] args) {
ComparableTest[] comparableTests = new ComparableTest[5];
comparableTests[0] = new ComparableTest(1,"孙悟空");
//其中id属性相等,这里就会比较String属性。
comparableTests[1] = new ComparableTest(25,"猪八戒");
comparableTests[2] = new ComparableTest(25,"鲁班");
comparableTests[3] = new ComparableTest(89,"孙尚香");
comparableTests[4] = new ComparableTest(74,"百里守约");
//重写时候调用Arrays工具类sort方法直接进行排序
Arrays.sort(comparableTests);
//输出验证
System.out.println(Arrays.toString(comparableTests));
}
测试结果
[ComparableTest{id=1, name='孙悟空'},
ComparableTest{id=25, name='猪八戒'},
ComparableTest{id=25, name='鲁班'},
ComparableTest{id=74, name='百里守约'},
ComparableTest{id=89, name='孙尚香'}]
Comparable总结
通过Comparable接口实现比较大小,实际上就是通过compareTo方法进行本对象与传入对象进行属性的逐个比较,如果第一个属性相等,那么就比较第二个,以此类推。
特别的,如果类中含有引用数据(如String或自定义类),那么想要通过引用数据进行比较大小,则引用数据属性也必须实现Comparable接口,如本例中的String类型属性,String就已经实现的Comparable接口。
Comparator接口
相比于Comparable接口更加灵活,所以被称为自定义排序,本类可以不直接实现此接口,而是在调用Arrays.sort()方法时传入实现此接口的对象即可。
基础待比较类
public class ComparatorTest {
private Integer id;
private String name;
public ComparatorTest(Integer id, String name) {
this.id = id;
this.name = name;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ComparableTest{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
测试
public static void main(String[] args) {
ComparatorTest[] ComparatorTests = new ComparatorTest[5];
ComparatorTests[0] = new ComparatorTest(1,"孙悟空");
ComparatorTests[1] = new ComparatorTest(25,"猪八戒");
ComparatorTests[2] = new ComparatorTest(25,"鲁班");
ComparatorTests[3] = new ComparatorTest(89,"孙尚香");
ComparatorTests[4] = new ComparatorTest(74,"百里守约");
//重写时候调用Arrays工具类sort方法直接进行排序
//这里直接采用匿名内部类写法重写compare方法
Arrays.sort(ComparatorTests, new Comparator<ComparatorTest>() {
@Override
public int compare(ComparatorTest o1, ComparatorTest o2) {
//Integer等基本数据类型包装类已经实现了Comparator接口
//直接调用即可
int compare = Integer.compare(o1.getId(), o2.getId());
//如果返回值不等于0,说明两属性不相等,直接返回对应值即可。
if (compare != 0){
return compare;
}
//如果相等,那就比较第二个属性String
//这里仍然调用String已经重写的compareTo方法
return o1.getName().compareTo(o2.getName());
}
});
//输出验证
System.out.println(Arrays.toString(ComparatorTests));
}
Integer包装类重写的compare方法
public static int compare(int x, int y) {
return (x < y) ? -1 : ((x == y) ? 0 : 1);
}
测试结果
[ComparableTest{id=1, name='孙悟空'},
ComparableTest{id=25, name='猪八戒'},
ComparableTest{id=25, name='鲁班'},
ComparableTest{id=74, name='百里守约'},
ComparableTest{id=89, name='孙尚香'}]
Comparator总结
相比Comparable接口,Comparator降低了耦合性,不需要本类直接实现接口,而是在调用比较时,直接传入实现接口的匿名类,重写compare方法。