先来看实现comparable接口的排序。
//在内部实现comparable接口,指定排序依据 public class Student implements Comparable<Student> { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Student(int age, String name) { super(); this.age = age; this.name = name; } /* (non Javadoc) * @Title: compareTo * @Description: 实现comparaTor()方法,来指定排序依据 * @param stu * @return * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override public int compareTo(Student stu) { return this.getName().compareTo(stu.getName());//定义成升序 } @Override public String toString() { return age + "\t" + name + "\n"; } }
//测试如下 public class ComparatableTest { public static void main(String[] args) { //定义一个学生数据库 Student[] allStudents = new Student[4]; //初始化学生数据库 allStudents[0] = new Student(1,"a"); allStudents[1] = new Student(2,"b"); allStudents[2] = new Student(3,"c"); allStudents[3] = new Student(4,"d"); for(int i=0;i<allStudents.length;i++){ allStudents[i].setAge(i*10); } //不同点 Arrays.sort(allStudents);//通过student内部的compareTo()方法比较排序。 //显示学生信息 System.out.println("年龄" + "\t姓名"); for(int i=0;i<allStudents.length;i++){ System.out.print(allStudents[i]); } }
再来看看实现comparator接口的排序。
//这里并未实现comparable接口 public class Student2 { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Student2(int age, String name) { super(); this.age = age; this.name = name; } @Override public String toString() { return age + "\t" + name + "\n"; } }
//在外部实现comparator接口,构建自己的排序实现类,指定排序依据 public class StudentSortWithName implements Comparator<Student2> { /* (non Javadoc) * @Title: compare * @Description: 实现Comparator的compare()方法,定义name为排序依据 * @param o1 * @param o2 * @return * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(Student2 o1, Student2 o2) { return o1.getName().compareTo(o2.getName()); } }
//在外部实现comparator接口,构建自己的排序实现类,指定排序依据 public class StudentSortWithAge implements Comparator<Student2> { /* (non Javadoc) * @Title: compare * @Description: 实现Comparator的compare()方法,定义age为排序依据, * @param o1 * @param o2 * @return * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) */ @Override public int compare(Student2 o1, Student2 o2) { if(o1.getAge() > o2.getAge()){ return 1; }else if(o1.getAge() < o2.getAge()){ return -1; }else{ return 0; } } }
//测试comparator public class ComparatorTest { public static void main(String[] args) { //定义一个学生数据库 Student2[] allStudents = new Student2[4]; //初始化学生数据库 allStudents[0] = new Student2(1,"a"); allStudents[1] = new Student2(2,"b"); allStudents[2] = new Student2(3,"c"); allStudents[3] = new Student2(4,"d"); for(int i=0;i<allStudents.length;i++){ allStudents[i].setAge(i*10); } //显示学生信息 System.out.println("年龄" + "\t姓名"); for(int i=0;i<allStudents.length;i++){ System.out.print(allStudents[i]); } Arrays.sort(allStudents,new StudentSortWithName());//不同点, //通过 <T> void java.util.Arrays.sort(T[] a, Comparator<? super T> c)来调用自己构建的排序实现类 //显示学生信息 System.out.println("年龄" + "\t姓名"); for(int i=0;i<allStudents.length;i++){ System.out.print(allStudents[i]); } } }
小结:Comparatable接口必须由需要排序的多元素类本身来实现,且在其内部重写comparaTo()方法;Comparator接口是在需要排序的多元素类的外部(即使用外部类)来实现,且必须在该外部类中重写compara()方法。
两者的比较
说到比较器我们第一时间会想到equals,但是equals是用来比较是否相等的,Comparator或者Comparable是用来比较顺序的(也就是排序)。
内部比较器(Comparable接口)和外部比较器(Comparator接口)。
package java.lang;
public interface Comparable
{
public int compareTo(T o);
1)如果此对象(调用比较器方法的对象)大于指定对象(目标比较对象),返回正整数
2)如果此对象小于指定对象,返回负整数
3)如果此对象等于指定对象,返回零
}
新定义一个类,类名随意,但这个类必须实现Comparator接口,重写compare方法,我们把这个称作外部比较器。
package java.util;
public interface Comparator {
int compare(T o1, T o2);
1)如果o1大于o2,则返回正整数;
2)如果o1小于o2,则返回负整数
3)如果o1等于o2,则返回零
boolean equals(Object obj); //你是不是想问为什么这个方法不需要重写?对不起,我也不是特别清楚,但通常是把这个方法忽略掉,如果
必须要个说法,你可以说这个方法被默认实现了。
}
1.我们自定义一个类时,可以选择内部比较器,内部比较器很符合java封装的思想,也就是高内聚,但是!但是!但是!我们平时用到的类往往不是自定义的,而是别人已经写好并且已编译的类,我们只能调用,不能修改其源代码,这时我们就只能用外部比较器了。
2.还有种情况,我们用到的还是别人已经写好并且已编译的类,他写这个类的时候恰好也实现了内部比较器(我们常用的有基本类型的封装类,String,Date),但是他定义的这种比较方法,不是我们想要的(举个例子,integer的内部比较器是按照数字大小进行比较排序,但是我们的需求是按照数字的绝对值进行排序,这就很尴尬了),这时我们就只能用外部比较器了。
最最常见的应用还是用在集合(list)和数组的sort()方法中,如果我们想用sort()方法,必须实现存储元素对象的内部比较器或者自定义一个用于存储元素对象之间的外部比较器,不然用sort()方法的时候容器会报错,它不知道用哪种方式进行排序。
下面贴个比较器和sort方法的应用Demo,自己体会一哈:
}
/**
你要是还不理解外部和内部比较器的区别,最后再送你个例子:
我和黄晓明谁比较帅?在我心里是不知道如何比较的,我不知道判断帅的标准是什么(这就相当于“我”这个实例,本身没有内部比较器),我现在很想很想知道答案,有两个方法,第一个是上网查资料,查判断帅的标准是啥,然后再比较(也就是实现内部比较器),第二个就是找一个裁判a,他知道判断标准是啥,让他来判断我们两个谁帅(相当于定义了一个外部比较器类a)
package com.wangge; import java.util.ArrayList; import java.util.List; /** * @ClassName AAA * @Description TODO * @Author Wangzh8QvQ * @Date 2020/3/16 16:21 * @Version 1.0 */ public class AAA { public static void main(String[] args) { List<Person> l = new ArrayList<>(); for (int i = 0; i < 10; i++) { Person p = new Person(); p.age = (int) (Math.random() * 100); p.money = (int) (Math.random() * 100000); l.add(p); } /** * 实现Comparable接口 */ // Collections.sort(l); /** * Comparator使用方法。即自定义比较器。这种耦合度比较低。 */ //使用工具类 // Collections.sort(l, (o1, o2) -> o1.money-o2.money); //使用集合提供的sort方法。 l.sort((a, b) -> a.age - b.age); l.forEach(s -> System.out.println(s)); } } class Person implements Comparable<Person> { int age; int money; @Override public int compareTo(Person o) { return this.age - o.age; } @Override public String toString() { return "Person{" + "age=" + age + ", money=" + money + '}'; } }
<p>comparable和comparator都是可以对集合中元素进行比较、排序。</p><p>comparable是内部比较,可以对基本数据类型(int等)进行比较</p><p>comparator是外部比较器,对类进行比较,比如学生类中的年龄、成绩、学号等进行比较</p>
就是集合中已经自带了comparable接口,比如你比较int类型的自带的comparable就会采用自然顺序排序,但是如果这个不满足你的要求,比如你想对整数加上绝对值之后的值排序,那么就要自定义一个comparator进行自定义的排序规则