常见的接口与类 -- Comparator
Comparable和Comparator
Java提供了一个用于比较的接口Comparable,实际上Java中还提供了一个接口Comparator,该接口也具有比较的功能,其更注重的是比较容器,然后对其排序。
- Comparable在java.lang包中,它是排序接口,若一个类实现了Comparable接口,就意味着“该类支持排序”,其相当于“内部比较器”。
- Comparator在java.util包中,它是比较器,我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序,其相当于“外部比较器”。
两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码。 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。
使用场景
- 排序
需要比较两个对象谁排在前谁排在后 - 分组
需要比较两个对象是否是属于同一组
接口方法
作为接口Comparator提供了两个抽象方法:
返回值 | 方法 |
---|---|
int | compare(T o1, T o2) 比较用来排序的两个参数 |
boolean | equals(Object obj) 指示某个其他对象是否“等于”此 Comparator |
Compare() 比较用来排序的两个参数。根据第一个参数小于、等于或大于第二个参数分别返回负整数、零或正整数(>0是代表自然正序排列,<0代表自然排序倒序)。
- return 1 时,按照从小到大排序
- return 0 时,原位置不动
- return -1 时,按照从大到小排序
类实现Comparator接口时,只需要实现compare方法,因为Java中类都继承于Object类,而Object类默认实现了equals方法,所以不需要必须去实现equals方法。
实践操作
排序时,两个对象比较的结果有三种:大于,等于,小于。
分组时,两个对象比较的结果只有两种:等于(两个对象属于同一组),不等于(两个对象属于不同组)。
排序
降序排列:
public class Main {
public static void main(String[] args) {
// write your code here
//要想改变默认的排列顺序,不能使用基本类型(int,double, char),而要使用它们对应的类
Integer[] nums = {2,4345,224,563,24,45};
Arrays.sort(nums,new MyComparator());
System.out.println(Arrays.toString(nums));
}
}
class MyComparator implements Comparator<Integer> {
//如果o1小于o2,我们就返回正值(自然排序),如果o1大于o2我们就返回负值(自然倒序)
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1; //降序
}
}
结果:
[4345, 563, 224, 45, 24, 2]
二维数组排序:
public static void main(String[] args){
int[][] points = {{7,16},{2,8},{3,6},{10,12}};
Arrays.sort(points, new Comparator<int[]>() {
public int compare(int[] point1, int[] point2) {
return point1[1] - point2[1]; //右边界升序
}
});
for(int[] arr:points){
System.out.println(Arrays.toString(arr));
}
}
结果:
[3, 6]
[2, 8]
[10, 12]
[7, 16]
分组
public class GroupTest {
class Apple {
public String color;
public int weight;
public Apple(String color, int weight) {
super();
this.color = color;
this.weight = weight;
}
@Override
public String toString() {
return "Apple [color=" + color + ", weight=" + weight + "]";
}
}
public static <T> List<List<T>> divider(Collection<T> datas, Comparator<? super T> c) {
List<List<T>> result = new ArrayList<List<T>>();
for (T t : datas) {
boolean isSameGroup = false;
for (int j = 0; j < result.size(); j++) {
if (c.compare(t, result.get(j).get(0)) == 0) {
isSameGroup = true;
result.get(j).add(t);
break;
}
}
if (!isSameGroup) {
// 创建
List<T> innerList = new ArrayList<T>();
result.add(innerList);
innerList.add(t);
}
}
return result;
}
public static void main(String[] args) {
List<Apple> list = new ArrayList<>();
list.add(new GroupTest().new Apple("红", 205));
list.add(new GroupTest().new Apple("红", 131));
list.add(new GroupTest().new Apple("绿", 248));
list.add(new GroupTest().new Apple("绿", 153));
list.add(new GroupTest().new Apple("黄", 119));
list.add(new GroupTest().new Apple("黄", 224));
List<List<Apple>> byColors = divider(list, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
// 按颜色分组
return o1.color.compareTo(o2.color);
}
});
System.out.println("按颜色分组" + byColors);
List<List<Apple>> byWeight = divider(list, new Comparator<Apple>() {
@Override
public int compare(Apple o1, Apple o2) {
// 按重量级
return (o1.weight / 100 == o2.weight / 100) ? 0 : 1;
}
});
System.out.println("按重量级分组" + byWeight);
}
}
结果:
// 按颜色分组
[
[Apple [color=红, weight=205],Apple [color=红, weight=131]],
[Apple [color=绿, weight=248],Apple [color=绿, weight=153]],
[Apple [color=黄, weight=119],Apple [color=黄, weight=224]]
]
//按重量级分组
[
[Apple [color=红, weight=205],Apple [color=绿, weight=248],Apple [color=黄, weight=224]],
[Apple [color=红, weight=131],Apple [color=绿, weight=153],Apple [color=黄, weight=119]]
]