Comparable
比较对象大小
Comparable
接口和 Comparator
接口都是 Java 中用于排序的接口,它们在实现类对象之间比较大小、排序等方面发挥了重要作用:
Comparable
接口实际上是出自java.lang
包 它有一个compareTo(Object obj)
方法用来排序Comparator
接口实际上是出自java.util
包它有一个compare(Object obj1, Object obj2)
方法用来排序
比较对象大小的经典应用---排序
如果在使用 Arrays.sort( 数组 )或Collections.sort(Collection 集合 ) 方法时,TreeSet 和 TreeMap时元素默认按照Comparable 比较规则排序;也可以单独为 Arrays.sort( 数组 )或 Collections.sort(Collection集合 ) 方法,TreeSet 和 TreeMap 指定 Comparator 定制比较器对象。
原则:在使用Collection的sort排序的集合元素都必须是Comparable接口的实现类,表示该类是可以比较的。
Comparable(Integer、String)
String、包装类都已经实现了Comparable接口,并且重写了compareTo()方法。我们是可以直接使用的。
//comparable接口
public interface Comparable<T> {
public int compareTo(T o);
}
public static void main(String[] args) {
//public final class Integer extends Number implements Comparable<Integer>
List<Integer> list0 = new ArrayList<>();//Integer是隐藏伏笔,集合中只能存储引用类型
for (int i = 0; i < 10; i++) {
//随机生成1-100的整数
int val = (int)(Math.random() * 100 + 1);
list0.add(val);
}
System.out.println("list0集合排序前"+list0);//[75, 73, 29, 82, 42, 10, 99, 83, 85, 8]
Collections.sort(list0);
System.out.println("list0集合排序后"+list0);//[8, 10, 29, 42, 73, 75, 82, 83, 85, 99]
System.out.println("=======================================");
//public final class String implements java.io.Serializable, Comparable<String>, CharSequence
List<String> list1 = new ArrayList<>();
list1.add("Alive");
list1.add("Rose");
list1.add("Jack");
list1.add("Noname");
System.out.println("list1集合排序前"+list1);//[Alive, Rose, Jack, Noname]
Collections.sort(list1);
System.out.println("list1集合排序后"+list1);//[Alive, Jack, Noname, Rose]
}
之所以能调用Collections.sort()对list集合排序是因为 Integer、String类都实现了Comparable接口,所以在对list0和list1集合排序时没有报错。
运行结果:
Comparable(Goods 商品类)
我们自定义的类(Goods 商品类),也想调用Collections.sort()实现排序,那就必须在定义类的时实现Comparable接口,重写compareTo()方法。
重写compareTo(obj)的规则:
如果当前对象this大于形参对象obj,则返回正整数。
如果当前对象this小于形参对象obj,则返回负整数。
如果当前对象this等于形参对象obj,则返回零。
public class Goods implements Comparable<Goods>{
String name;
Double price;
public Goods() {
}
public Goods(String name, Double price) {
this.name = name;
this.price = price;
}
@Override
public int compareTo(Goods goods) {
//使商品的排序是按照价格从低到高排序
if(this.price>goods.price){
return 1;
}else if(this.price<goods.price){
return -1;
}else {
return 0;
}
}
}
测试:
public static void main(String[] args) { Goods g1 = new Goods("毛巾", 12.8); Goods g2 = new Goods("牙刷", 5.6); Goods g3 = new Goods("洗面奶", 108.1); Goods g4 = new Goods("鞋刷", 1.3); ArrayList<Goods> list = new ArrayList<>(); list.add(g1); list.add(g2); list.add(g3); list.add(g4); System.out.println("排序前:"); for (Goods goods : list) { System.out.println("商品:"+goods.name+" ,价格"+goods.price); } System.out.println("=================================="); Collections.sort(list); System.out.println("排序后:"); for (Goods goods : list) { System.out.println("商品:"+goods.name+" ,价格"+goods.price); } }
运行结果:
那么,新的需求来了。
我要先把商品按照价格从低到高排序,要是价格一样的话,那就按照商品名称从低到高排序。
public int compareTo(Goods goods) {
//使商品的排序是按照价格从低到高排序
if(this.price>goods.price){
return 1;
}else if(this.price<goods.price){
return -1;
}else {
//商品名称是字符串嘛,直接调String类重写过的compareTo()方法,比较字符串大小
return this.name.compareTo(goods.name);
}
}
Comparator定制排序
Comparator应用场景
public interface Comparator<T> {
int compare(T o1, T o2);
}
是不是觉得学了comparable自然排序就够用了,虽然我也这么想,但是还不行(⊙o⊙)…。
某些情况还是需要用定制排序的。comparator应用的俩种情况,
- 一种是人家写好你不能改的类,比如jdk啥的。
- 另一种像String那样的已经实现过Comparable接口的。但是你不想使用人家写好的那种排序方式。
利用重写的方法 :int compare(T o1,T o2),比较o1和o2的大小:
如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2
Comparator(String)
Comparable像是一劳永逸,而Comparator就像是临时的,你会越来越有这种感觉的。
怎么使用Comparator接口呢?
实现接口,重写compare(Objet o1,Object o2)方法。注意Comparator也是函数式接口
如下,使用匿名内部类实现了Comparator接口,临时改变字符串默认排序规则。
public static void main(String[] args) {
String[] arr = {"AA", "DD", "BB", "CC"};
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));
}
//可以使用lambda简化
public static void main(String[] args) {
String[] arr = {"AA", "DD", "BB", "CC"};
System.out.println("排序前"+Arrays.toString(arr));
Arrays.sort(arr, (o1, o2) -> {
//改变字符串排序规则,使得字符串从大到小排序
return -o1.compareTo(o2);
});
System.out.println("定制排序后"+Arrays.toString(arr));
}
运行结果:
Comparator(Goods 商品类)
定制排序自定义的Goods类,临时改变排序规则:
使用定制排序改变默认的自然排序规则,我们让商品价格从高到低排序
public static void main(String[] args) {
Goods g1 = new Goods("毛巾", 12.8);
Goods g2 = new Goods("牙刷", 5.6);
Goods g3 = new Goods("洗面奶", 108.1);
Goods g4 = new Goods("鞋刷", 1.3);
ArrayList<Goods> list = new ArrayList<>();
list.add(g1);
list.add(g2);
list.add(g3);
list.add(g4);
System.out.println("排序前:");
for (Goods goods : list) {
System.out.println("商品:"+goods.name+" ,价格"+goods.price);
}
System.out.println("==================================");
Collections.sort(list);
System.out.println("默认的自然排序后:");
for (Goods goods : list) {
System.out.println("商品:"+goods.name+" ,价格"+goods.price);
}
System.out.println("==================================");
//使用定制排序改变默认的自然排序规则,我们让商品价格从高到低排序
Collections.sort(list, new Comparator<Goods>() {
@Override
public int compare(Goods o1, Goods o2) {
return -o1.compareTo(o2);
}
});
System.out.println("定制排序后:");
for (Goods goods : list) {
System.out.println("商品:"+goods.name+" ,价格"+goods.price);
}
}
运行结果: