[转载] 比较器(Comparable和Comparator)、自然排序、定制排序
参考链接: Java比较器接口与示例写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的。 这博客是对自己学习的一点点总结及记录,如果您对 Java、算法 感兴趣,可以关注我的动态,我们一起学习。 用知识改变命运,让我们的家人过上更好的生活。比如Integer,double等基本类型数据,Java可以对他们进行比较排序,但
写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的。 这博客是对自己学习的一点点总结及记录,如果您对 Java、算法 感兴趣,可以关注我的动态,我们一起学习。 用知识改变命运,让我们的家人过上更好的生活。
比如Integer,double等基本类型数据,Java可以对他们进行比较排序,但是在 Java 中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题 。
目录
一、java中的sort()方法二、自然排序:Comparable1.自然排序的定义2.实现过程3.示例代码
三、定制排序 :Comparator1.实现过程2.示例代码
一、java中的sort()方法
在java.util.Collections类中有个sort()方法,主要是用来给数组排序
public class CompareTest1 {
@Test
public void test() {
String[] arr = new String[]{"AA", "SS", "FF", "OO", "EE", "HH"};
System.out.println("排序之前: " + Arrays.toString(arr));
Arrays.sort(arr);
System.out.println("排序之后: " + Arrays.toString(arr));
}
}
代码执行结果:
排序之前: [AA, SS, FF, OO, EE, HH]
排序之后: [AA, EE, FF, HH, OO, SS]
需求:商场有一批水果,对水果的价格进行排序
水果类:
public class Fruit {
private String name;
private double price;
public Fruit() {
}
public Fruit(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
测试类:
public class CompareTest2 {
@Test
public void test() {
Fruit[] arr = new Fruit[5];
arr[0] = new Fruit("apple", 18);
arr[1] = new Fruit("pear", 6);
arr[2] = new Fruit("banana", 14);
arr[3] = new Fruit("watermelon", 26);
arr[4] = new Fruit("tomato", 6);
System.out.println("排序之前: " + Arrays.toString(arr));
// 排序
Arrays.sort(arr);
System.out.println("排序之后: " + Arrays.toString(arr));
}
}
程序将会报错:
java.lang.ClassCastException: xxx.Fruit cannot be cast to java.lang.Comparable
报错原因:类型转换错误。
为了解决这个错误,对象之间的排序将用到比较器。
Java 实现对象排序的方式有两种:
自然排序: java.lang.Comparable
定制排序: java.util.Comparator
二、自然排序:Comparable
1.自然排序的定义
Comparable 接口强行对实现它的每个类的对象进行整体排序
2.实现过程
实现 Comparable接口的类必须实现 compareTo(Object obj) 方法,两个对象通过 compareTo方法的返回值来比较大小 。 ① 如果当前对象 this 大于形参对象 obj 则返回正整数; ② 如果当前对象 this 小于 形参对象 obj则返回 负整数; ③ 如果当前对象 this 等于 形参对象 obj 则返回零 。 实现 Comparable接口的对象列表(和数组)可以通过 Collections.sort 或 Arrays.sort 进行自动排序。 实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器
为了解决类型转换错误,在水果类里面实现Comparable接口。
3.示例代码
水果类:
public class Fruit implements Comparable<Fruit> {
private String name;
private double price;
public Fruit() {
}
public Fruit(String name, double price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Fruit{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
// 水果价格从低到高进行排序,若价格相同则按水果名称从高到低排序
@Override
public int compareTo(Fruit fruit) {
if (this.price > fruit.price) {
return 1;
} else if (this.price < fruit.price) {
return -1;
} else {
// this.name.compareTo(fruit.name) 按名称从低到高,前面加负号,表示相反
return -this.name.compareTo(fruit.name);
}
}
}
注:测试类代码同Test2 代码执行结果:
排序之前: [Fruit{name='apple', price=18.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='tomato', price=6.0}]
排序之后: [Fruit{name='tomato', price=6.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='apple', price=18.0}, Fruit{name='watermelon', price=26.0}]
三、定制排序 :Comparator
在实际开发中,遇到当元素的类型实现了Comparable 接口,但是它的排序方式不适合当前的操作;或者根本没有实现Comparable 接口,而又不方便修改代码。那么可以考虑使用 Comparator 的对象进行排序。
1.实现过程
定义一个比较器对象; 重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小: ① 如果方法返回正整数,则表示 o1 大于 o2 ; ② 如果方法返回 0 ,表示相等; ③ 如果方法返回负整数,表示o1 小于 o2 。
可以 将 Comparator 传递给 sort 方法,从而允许在排序顺序上实现精确控制 。
2.示例代码
public class CompareTest3 {
/**
* 按字符从大到小进行排序
*/
@Test
public void test() {
String[] arr = new String[]{"AA", "CC", "KK", "MM", "GG", "FF", "DD"};
System.out.println("原来的字符串: " + Arrays.toString(arr));
Arrays.sort(arr, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return -o1.compareTo(o2);
}
});
System.out.println("按字符从大到小排序后的字符串: " + Arrays.toString(arr));
}
}
代码执行结果:
原来的字符串: [AA, CC, KK, MM, GG, FF, DD]
按字符从大到小排序后的字符串: [MM, KK, GG, FF, DD, CC, AA]
对水果的价格进行排序
注:水果类同前,节省篇幅,在此不再重复。
public class CompareTest4 {
@Test
public void test() {
Fruit[] arr = new Fruit[5];
arr[0] = new Fruit("apple", 18);
arr[1] = new Fruit("pear", 6);
arr[2] = new Fruit("banana", 14);
arr[3] = new Fruit("watermelon", 26);
arr[4] = new Fruit("watermelon", 6);
System.out.println("排序之前: " + Arrays.toString(arr));
Arrays.sort(arr, new Comparator<Fruit>() {
// 按照水果名称从低到高排序,若名称相同则按照价格从高到低排序
@Override
public int compare(Fruit o1, Fruit o2) {
if (o1.getName().equals(o2.getName())) {
return -Double.compare(o1.getPrice(), o2.getPrice());
} else {
return o1.getName().compareTo(o2.getName());
}
}
});
System.out.println("排序之后: " + Arrays.toString(arr));
}
}
代码执行结果:
排序之前: [Fruit{name='apple', price=18.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='watermelon', price=6.0}]
排序之后: [Fruit{name='apple', price=18.0}, Fruit{name='banana', price=14.0}, Fruit{name='pear', price=6.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='watermelon', price=6.0}]
当定制排序和自然排序同时存在时,最终的排序结果是按照定制排序进行排序的。
上一篇 聊聊 StringBuffer 与 StringBuilder
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)