深入理解Java比较器(Comparable和Comparator)
若一个类实现了Comparable接口,就意味着该类支持排序。实现了 Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。对于我们想从其他成员变量来排序,那么此时我们就需要比较器来实现。
深入理解Java比较器(Comparable和Comparator)
文章目录
在java中经常涉及到 对象数组的比较的情况,常见的有两种方法来处理:
- 继承comparable接口,并实现compareTo()方法
- 定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法
一、 Comparable
若一个类实现了Comparable接口,就意味着该类支持排序。实现了 Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
此外,实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器。
此接口只有一个方法compare,比较此对象与指定对象的顺序,如果该对象小于、等于或大于指定 对象,则分别返回负整数、零或正整数。
1、Comparable 接口定义
Comparable 接口仅仅只包括一个函数,如下
package java.lang;
import java.util.*;
public interface Comparable {
//必须实现的抽象方法
public int compareTo(T o);
}
说明:根据这个方法的返回值来判断
大于0:说明前一个比后一个大
小于0:说明前一个小于后一个
等于0:说明这两个一样大
示例:
这里有一个员工类Employee1,我们需要堆员工实体对员工的工资进行排序,所以这里用实现Comparable接口,重写compareTo方法
import java.util.Arrays;
public class Employee1 implements Comparable<Employee1>{
private String name;
private double salary;
public Employee1(String name , double salary){
this.name = name;
this.salary = salary;
}
public Employee1(String name , double salary){
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
@Override
public String toString() {
return "Employee1{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
/**
* 重写排序规则:
* 定义我们的排序规则,用salary来排序
* @param other
* @return
*/
@Override
public int compareTo(Employee1 other) {
return Double.compare(salary,other.salary);
}
}
此时:我们重写了compareTo方法,可以看出是用成员变量salary进行了比较,当前一个对象小于后一个对象时,返回小于0,反之大于0,等于则返回0.
测试类:
public static void main(String[] args) {
Employee1[] temp=new Employee1[4];
temp[0]=new Employee1("张三",150);
temp[1]=new Employee1("李四",120);
temp[2]=new Employee1("王五",135);
temp[3]=new Employee1("小花",80);
Arrays.sort(temp);
for (Employee1 employee1 : temp) {
System.out.println(employee1.toString());
}
}
输出结果:
总结:
此时因为我们已经重写了compareTo方法,这里我们用实现Comparable的方法进行了对象的排序。
二、Comparator 比较器接口
背景:
我们若需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么,我们可以建立一个“该类的比较器”来进行排序。这个“比较器”只需要实现Comparator接口即可。也就是说,我们可以通过“实现Comparator类来新建一个比较器”,然后通过该比较器对类进行排序。
2.1、Comparator接口原码
特别说明
若一个类要实现Comparator接口:它一定要实现compareTo(T o1, T o2) 函数,但可以不实现 equals(Object obj) 函数。
为什么可以不实现 equals(Object obj) 函数呢? 因为任何类,默认都是已经实现了equals(Object obj)的。 Java中的一切类都是继承于java.lang.Object,在Object.java中实现了equals(Object obj)函数;所以,其它所有的类也相当于都实现了该函数。
package java.util;
public interface Comparator {
int compare(T o1, T o2);
boolean equals(Object obj);
}
int compare()方法
返回值为:
小于0–>前一个对象小于后一个对象
大于0–>前一个对象大于后一个对象
等于0–>前一个对象等于后一个对象
2.2具体代码示例
背景
此时,我们在Employee1类的基础上,我们再添加一个升高,但是这个类的依旧实现了Comparable接口,重写了compareTo方法,并且这个方法按照工资薪水排序,此时我们如何能都不改变代码的前提下,重新对升高排序呢?
此时就引入了Comparator接口,我们实现这个接口的int compare方法,具体如下
import java.util.Arrays;
import java.util.Comparator;
public class Employee
{
private String name;
private double salary; // 年薪
// 构造器
public Employee(String name, double salary)
{
this.name = name;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
@Override
public String toString() {
return "Employee{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
// 按照薪水排序的比较器
static class salaryComparator implements Comparator<Employee>{
@Override
public int compare(Employee o1, Employee o2) {
return Double.compare(o1.salary,o2.salary);
}
}
public static void main(String[] args) {
Employee e1 = new Employee("Tom", 8000);
Employee e2 = new Employee("Jerry", 3000);
Employee e3 = new Employee("Alice", 6000);
Employee e4 = new Employee("Tim", 5000);
Employee[] employees = {e1, e2, e3 ,e4};
salaryComparator salaryComparator = new salaryComparator();
Arrays.sort(employees, salaryComparator);
// 按照薪水排序
for (Employee employee : employees) {
System.out.println(employee.toString());
}
}
}
测试:
public static void main(String[] args) {
Employee e1 = new Employee("Tom", 8000);
Employee e2 = new Employee("Jerry", 3000);
Employee e3 = new Employee("Alice", 6000);
Employee e4 = new Employee("Tim", 5000);
Employee[] employees = {e1, e2, e3 ,e4};
salaryComparator salaryComparator = new salaryComparator();
Arrays.sort(employees, salaryComparator);
// 按照薪水排序
for (Employee employee : employees) {
System.out.println(employee.toString());
}
}
对于核心排序代码,我们也可以用lambda表达式来编写:
Arrays.sort(staff,((o1, o2) -> {
if(o1.getHeight()==o2.getHeight()){
return 0;
}
return o1.getHeight()-o2.getHeight();
})) ;
原因
从Arrays.sort()源码的角度分析,sort方法接收的参数类型,一个为数组类型,一个为Comparator对象,因为Comparator为接口所以不能实例化,但是我们可以用多态来指向它,我们可以声明Comparator的实现类对象指向这个接口,此时就可以调用这个接口。
当我们用lambda表达式时,也是创建了这个Comparator接口的具体实现方法,所以两者都可以进行排序,看读者的自己。
输出结果:
此时我们的这个数组对象就已经按照升高排序,实现需求。
三、Comparator 和 Comparable 比较
Comparable是排序接口;若一个类实现了Comparable接口,就意味着“该类支持排序”。
而Comparator是比较器;我们若需要控制某个类的次序,可以建立一个“该类的比较器”来进行排序。
的自己。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)