今天在看TreeMap的时候总是出现关于比较的问题,刚开始对Comparable和Comparator不是很理解,想着这两个都是差不多的比较器,但是随着看着的深入发现不仅仅只是比较的作用,还可以用来排序的作用。
首先看看使用两个比较器所需要的函数:
Comparable:使用Comparable一般都是通过类去实现此接口的,在类的内部去实现这个方法,所以一般人也称作为内部比较器(相对于Comparator来说),有好多的java原生的类都是实现了这个接口,比如String,....。
public interface Comparable<T> {
public int compareTo(T o);
}
Comparator:使用Comparator一般都是写一个类去实现Comparator接口,让这个类作为专用的比较器,在需要比较器的地方当做参数传入进去,这样就可以使用比较器了。
public interface Comparator<T> {
int compare(T o1, T o2);
}
使用Comparable:
public class PersonImplementComparable implements Comparable<PersonImplementComparable>{
private String name;
private int age;
private String sex;
private Double height;
private Double weight;
public PersonImplementComparable() {
}
public PersonImplementComparable(String name, int age, String sex, Double height, Double weight) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
@Override
public String toString() {
return "PersonImplementComparable{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", height=" + height +
", weight=" + weight +
'}';
}
@Override
public int compareTo(PersonImplementComparable o) {
if(this.getAge()-o.getAge()>0){
return 1;
}else if(this.getAge()-o.getAge()<0){
return -1;
}else{
if(this.getHeight()-o.getHeight()>0){
return 1;
}else if(this.getHeight()-o.getHeight()<0){
return -1;
}else{
if(this.getWeight()-o.getWeight()>0){
return 1;
}else if(this.getWeight()-o.getWeight()<0){
return -1;
}else{
return 0;
}
}
}
}
}
@Test
public void test(){
PersonImplementComparable personImplementComparable1=new PersonImplementComparable("z1",18,"boy",189.0,140.0);
PersonImplementComparable personImplementComparable2=new PersonImplementComparable("z2",18,"girl",189.0,170.0);
PersonImplementComparable personImplementComparable3=new PersonImplementComparable("z3",18,"girl",189.0,150.0);
PersonImplementComparable personImplementComparable4=new PersonImplementComparable("z4",20,"girl",190.0,170.0);
PersonImplementComparable personImplementComparable5=new PersonImplementComparable("z5",19,"girl",170.0,170.0);
List<PersonImplementComparable> personImplementComparableList=new ArrayList<PersonImplementComparable>();
personImplementComparableList.add(personImplementComparable1);
personImplementComparableList.add(personImplementComparable2);
personImplementComparableList.add(personImplementComparable3);
personImplementComparableList.add(personImplementComparable4);
personImplementComparableList.add(personImplementComparable5);
for(PersonImplementComparable personImplementComparable:personImplementComparableList){
System.out.println(personImplementComparable);
}
System.out.println("---------------------------------------------------------------------------");
Collections.sort(personImplementComparableList);
for(PersonImplementComparable personImplementComparable:personImplementComparableList){
System.out.println(personImplementComparable);
}
}
排序前后的结果:
personImplementComparable{name='z1', age=18, sex='boy', height=189.0, weight=140.0}
PersonImplementComparable{name='z2', age=18, sex='girl', height=189.0, weight=170.0}
PersonImplementComparable{name='z3', age=18, sex='girl', height=189.0, weight=150.0}
PersonImplementComparable{name='z4', age=20, sex='girl', height=190.0, weight=170.0}
PersonImplementComparable{name='z5', age=19, sex='girl', height=170.0, weight=170.0}
---------------------------------------------------------------------------
PersonImplementComparable{name='z1', age=18, sex='boy', height=189.0, weight=140.0}
PersonImplementComparable{name='z3', age=18, sex='girl', height=189.0, weight=150.0}
PersonImplementComparable{name='z2', age=18, sex='girl', height=189.0, weight=170.0}
PersonImplementComparable{name='z5', age=19, sex='girl', height=170.0, weight=170.0}
PersonImplementComparable{name='z4', age=20, sex='girl', height=190.0, weight=170.0}
使用Comparator:
public class Person {
private String name;
private int age;
private String sex;
private Double height;
private Double weight;
public Person() {
}
public Person(String name, int age, String sex, Double height, Double weight) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.weight = weight;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public Double getHeight() {
return height;
}
public void setHeight(Double height) {
this.height = height;
}
public Double getWeight() {
return weight;
}
public void setWeight(Double weight) {
this.weight = weight;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", sex='" + sex + '\'' +
", height=" + height +
", weight=" + weight +
'}';
}
}
public class PersonComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
if(p1.getAge()-p2.getAge()>0){
return 1;
}else if(p1.getAge()-p2.getAge()<0){
return -1;
}else{
if(p1.getHeight()-p2.getHeight()>0){
return 1;
}else if(p1.getHeight()-p2.getHeight()<0){
return -1;
}else{
if(p1.getWeight()-p2.getWeight()>0){
return 1;
}else if(p1.getWeight()-p2.getWeight()<0){
return -1;
}else{
return 0;
}
}
}
}
}
@Test
public void test1(){
Person p1=new Person("z1",18,"boy",189.0,140.0);
Person p2=new Person("z2",18,"girl",189.0,170.0);
Person p3=new Person("z3",18,"girl",189.0,150.0);
Person p4=new Person("z4",20,"girl",190.0,170.0);
Person p5=new Person("z5",19,"girl",170.0,170.0);
List<Person> personList=new ArrayList<Person>();
personList.add(p1);
personList.add(p2);
personList.add(p3);
personList.add(p4);
personList.add(p5);
for(Person personImplementComparable:personList){
System.out.println(personImplementComparable);
}
System.out.println("---------------------------------------------------------------------------");
PersonComparator personComparator=new PersonComparator();
Collections.sort(personList,personComparator);
for(Person personImplementComparable:personList){
System.out.println(personImplementComparable);
}
}
排序前后的结果:
Person{name='z1', age=18, sex='boy', height=189.0, weight=140.0}
Person{name='z2', age=18, sex='girl', height=189.0, weight=170.0}
Person{name='z3', age=18, sex='girl', height=189.0, weight=150.0}
Person{name='z4', age=20, sex='girl', height=190.0, weight=170.0}
Person{name='z5', age=19, sex='girl', height=170.0, weight=170.0}
---------------------------------------------------------------------------
Person{name='z1', age=18, sex='boy', height=189.0, weight=140.0}
Person{name='z3', age=18, sex='girl', height=189.0, weight=150.0}
Person{name='z2', age=18, sex='girl', height=189.0, weight=170.0}
Person{name='z5', age=19, sex='girl', height=170.0, weight=170.0}
Person{name='z4', age=20, sex='girl', height=190.0, weight=170.0}
通过以上的对比我们可以发现其实Comparable与Comparator这两个比较器是非常的有用的,使用Comparable的时候只能是让这个类实现接口,使其具有比较的功能,因为其需要override的函数compareTo(Object o),只要一个参数,所以只能用作内部的比较器,而使用Comparator的则是专门的建一个类实现Comparator作为比较器去用,可以单独的拿出来,不用捆绑到类上,在实际工作中可能会出现比较大小写字母的时候按照字母的顺序部分大小写,但是在java中String已经实现了compareTo,而且分大小写,我们知道A,D,a,d是这样排序的,如果使用自带的则是A,D,a,d,但是要求我们的结果是A,a,D,d,这时候就应该重新排序了
@Test
public void test(){
List<String> list=new ArrayList<String>();
list.add("A");
list.add("D");
list.add("a");
list.add("d");
list.add("C");
list.add("c");
System.out.println(list);
System.out.println("--------------------------------------------");
Collections.sort(list);
System.out.println(list);
System.out.println("---------------------------------------------");
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
if(o1==null||o2==null)
return 0;
return o1.toUpperCase().compareTo(o2.toUpperCase());
}
});
System.out.println(list);
}
[A, D, a, d, C, c]
--------------------------------------------
[A, C, D, a, c, d]
---------------------------------------------
[A, a, C, c, D, d],所以在使用的时候可以这样使Comparator与Comparable结合使用。写到这里相信有很多的人都想不明白,为什么我们只是提供了个比较排序的方法而已,并没有按照我们日常的那种排序想法是比较大小和调换位置,这些都是java的原生代码底层帮我们做的,流程如下:
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
一种是有排序参数的函数,一种没有,但是都会调用List中的这个函数:
default void sort(Comparator<? super E> c) {
Object[] a = this.toArray();
Arrays.sort(a, (Comparator) c);
ListIterator<E> i = this.listIterator();
for (Object e : a) {
i.next();
i.set((E) e);
}
}
然后调用Arrays中的方法:
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (c == null) {
sort(a);
} else {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, 0, a.length, c, null, 0, 0);
}
}
没有提供比较的则调用默认的排序方式,有比较器的按照提供的比较器进行比较。是由java自己写的交换位置从而进行完成排序。