一、背景
- Java中基本数据类型之间可以使用比较运算符>、<、>=、<=、==、!=等进行比较;
- 引用数据类型之间进行比较时,使用继承于Object类的equals方法,对象之间使用==进行比较时,默认调用equals方法,实质上比较的是对象所在地址;所以如果使用equals方法进行比较,主要对其进行重写;
- equals方法的缺点在于只能进行“相等”比较,无法比较大小关系;
二、两种方法
- 方式一,自然排序:自定义类本身实现java.lang.Comparable接口,并重写其compareTo方法;
- 方式二,定制排序:需要具体比较类实现java.util.Comparator接口,并重写其compare方法,使用前必须具有该比较类实例化对象;
方式一,自然排序:
- 内置类,如字符串、集合类等默认实现java.lang.Comparable接口,且重写其compareTo方法,默认排序方式为升序;
- 自定义类若想具备比较大小的能力,需要实现java.lang.Comparable接口,且重写其compareTo方法;
- 如果想改变排序方式为降序,则将此时compareTo方法的返回值取反即可。可理解为升序时将“大”的对象(返回值为正数)放在后面,在降序时则是想让其放在前面,此时想法让算法内部认为“大”的对象变“小”即可,所以将其返回值取反即可实现该功能;
此实现方式要求自定义类必须实现java.lang.Comparable接口,且重写其compareTo方法,一旦实现则该类永久具备比较大小的能力。
@Data
public class Book implements Comparable<Book>{
private int price;
private String bookName;
private String author;
public Book(){
}
public Book(int price, String bookName, String author) {
this.price = price;
this.bookName = bookName;
this.author = author;
}
@Override
public int compareTo(Book o) {
// return this.price-o.price; // 升序
return o.price-this.price; // 降序
}
}
// 自定义类实现Comparable接口,并重写其compareTo方法;
// 按照Book类的price属性大小由高到低进行排序
@Test
public void comparableTest(){
Book book1 = new Book(99, "《叶惠美》", "周杰伦");
Book book2 = new Book(88, "《Jay》", "周杰伦");
Book book3 = new Book(111, "《魔杰座》", "周杰伦");
// System.out.println(book1.compareTo(book2));
// System.out.println(book1.compareTo(book3));
Book[] books=new Book[]{
book1,book2,book3};
System.out.println("排序前:"+Arrays.toString(books));
Arrays.sort(books);
System.out.println("排序后:"+Arrays.toString(books));
}
排序前:[Book(price=99, bookName=《叶惠美》, author=周杰伦), Book(price=88, bookName=《Jay》, author=周杰伦), Book(price=111, bookName=《魔杰座》, author=周杰伦)]
排序后:[Book(price=111, bookName=《魔杰座》, author=周杰伦), Book(price=99, bookName=《叶惠美》, author=周杰伦), Book(price=88, bookName=《Jay》, author=周杰伦)]
方式二,定制排序:
- 有些类可能存在以下这些情况,此时需要用到定制排序:1)类内部并未实现java.lang.Comparable接口,且对其内部代码又不方便进行修改;2)类虽然实现java.lang.Comparable接口,具备比较大小的能力,但是当前排序方式不满足显示需求,则需要对其排序方式进行修改;
- 定制排序,需要实现一个具体比较类实现java.util.Comparator接口,并重写其compare方法,使用前必须具有该比较类实例化对象;
此实现方式要求自定义类进行比较之前,必须获取到一个对应该类的比较类对象,此时该自定义类临时具备特定方式的比较能力。
// Book对应比较器:实现Comparator接口,并重写其compare方法;
class BookComparator implements Comparator<Book>{
@Override
public int compare(Book o1, Book o2) {
return o1.getPrice()-o2.getPrice(); // 升序
}
}
@Test
public void comparatorTest(){
Book book1 = new Book(99, "《叶惠美》", "周杰伦");
Book book2 = new Book(88, "《Jay》", "周杰伦");
Book book3 = new Book(111, "《魔杰座》", "周杰伦");
// 获取该类对应比较器对象
BookComparator comparator = new BookComparator();
// System.out.println(comparator.compare(book1,book2));
// System.out.println(comparator.compare(book1,book3));
Book[] books=new Book[]{
book1,book2,book3};
System.out.println("排序前:"+Arrays.toString(books));
Arrays.sort(books,comparator);
System.out.println("排序后:"+Arrays.toString(books));
}
排序前:[Book(price=99, bookName=《叶惠美》, author=周杰伦), Book(price=88, bookName=《Jay》, author=周杰伦), Book(price=111, bookName=《魔杰座》, author=周杰伦)]
排序后:[Book(price=88, bookName=《Jay》, author=周杰伦), Book(price=99, bookName=《叶惠美》, author=周杰伦), Book(price=111, bookName=《魔杰座》, author=周杰伦)]
在平时使用时,我们很少单独创建一个比较器类,比如BookComparator,而是在类似Arrays.sort方法的参数中直接传入参数,使用匿名子类的方式,示例如下:
Arrays.sort(books, new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
return o1.getPrice()-o2.getPrice();
}
});
资料来源:尚硅谷