一、概述:
对一组数据进行排序(升序或降序),在Java中有很多方式,可以自己手写排序算法(冒泡、快速、二叉树排序等),但一般都采用JDK为我们提供的现有的2个接口,Comparable和Comparator。
二、相同点:
- 两者都是用来用作对象之间的比较,都可以自定义比较规则。
- 两者都是返回一个描述对象之间关系的int。
三、区别:
- Comparable是java.lang包下的,Comparator是java.util包的。
- 实现Comparable接口必须重写compareTo(T o)方法,实现Comparator接口必须重写compare(T o1,T o2)方法。.
- Comparable是内在比较器,实现这个接口的类的对象可以直接比较:this.compareTo(this),这个类也支持排序,由该类对象组成的集合可以直接使用Collections.sort方法排序,此外,“实现Comparable接口的类的对象”可以用作“有序映射(如TreeMap)”中的键或“有序集合(TreeSet)”中的元素,而不需要指定比较器。Comparator是外在比较器,如果想比较两个类又没有实现Comparable或者想实现自定义排序的,可以用Comparator。
- Comparator与Comparable同时存在的情况下,比较器Comparator优先级高。
- 使用Comparable需要修改原先的实体类,是属于一种自然排序,而Comparator 是不用修改原先的类的实现一个新的比较器 。Comparator实际应用广。
四、例子:
通俗来说,如果一个实体类实现了Comparable接口来实现排序规则,使用一段时间后,如果想去改变这个排序规则,基于“开闭原则”对修改关闭对扩展开放,我们可以通过Comparator接口来实现新的排序规则让实体类去采纳,使用一段时间后,如果还想改变,再通过Comparator接口实现一个新的排序规则即可。不影响类的封装性,易于扩展。
实体类Book实现了Comparable接口,比较规则是按书价大小。将多个Book对象存储在Set容器中,存储顺序是按照compareTo的规则。
package com.orange.sort;
public class Book implements Comparable<Book>{
private String bookName;
private int bookPrice;
public Book() {
}
public Book(String bookName, int bookPrice) {
this.bookName = bookName;
this.bookPrice = bookPrice;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public int getBookPrice() {
return bookPrice;
}
public void setBookPrice(int bookPrice) {
this.bookPrice = bookPrice;
}
@Override
public String toString() {
return "Book{" +
"bookName='" + bookName + '\'' +
", bookPrice='" + bookPrice + '\'' +
'}';
}
@Override
public int compareTo(Book o) {
int minusPrice=this.getBookPrice()-o.getBookPrice();
return minusPrice;
}
}
测试:
@Test
public void test(){
TreeSet<Book> set = new TreeSet<>();
Book book1 = new Book("A", 1);
Book book2 = new Book("B", 5);
Book book3 = new Book("C", 3);
Book book4 = new Book("D", 4);
set.add(book1);
set.add(book2);
set.add(book3);
set.add(book4);
for(Book book:set){
System.out.println(book);
}
}
结果:按照书价排序
Book{bookName='A', bookPrice='1'}
Book{bookName='C', bookPrice='3'}
Book{bookName='D', bookPrice='4'}
Book{bookName='B', bookPrice='5'}
针对上述例子,此时如果想改变排序规则,在不破坏原实体类的封装性的前提下,可实现Comparator接口制定新规则,在创建TreeSet时,传入Comparator:
public void test2(){
TreeSet<Book> set = new TreeSet<>(new Comparator<Book>() {
@Override
public int compare(Book o1, Book o2) {
return o1.getBookName().compareTo(o2.getBookName());
}
});
Book book1 = new Book("A", 1);
Book book2 = new Book("B", 5);
Book book3 = new Book("C", 3);
Book book4 = new Book("D", 4);
set.add(book1);
set.add(book2);
set.add(book3);
set.add(book4);
for(Book book:set){
System.out.println(book);
}
}
结果:按照书名排序
Book{bookName='A', bookPrice='1'}
Book{bookName='B', bookPrice='5'}
Book{bookName='C', bookPrice='3'}
Book{bookName='D', bookPrice='4'}