写在前面
本篇文章主要涉及到的是两个接口 Comparable
和 Comparator
接口
Comparable接口
Arrays类中的sort方法承诺可以对于对象数组进行排序,但是要满足下面的条件: 对象所属的类必须实现Comparable
接口。
下面是 Comparable
接口中的代码:
public interface{ int compraraT0(Object other); }
这说明,任何实现Comparable接口的类都需要包含compareTo方法,这个方法有一个Object参数,并且返回一个整数。
当然,这个接口还有一个没有明确说明的附加要求:在调用x.compareTo(y)的时候,这个compareTo方法必须确实能够比较两个对象,并返回比较的结果,即×和y哪一个更大。当x小于y时,返回一个负数;当x等于y时,返回0;否则返回一个正数
上面这个接口只有一个方法,而有些接口可能包含多个方法。稍后可以看到,接口还可以定义常量。不过,更重要的是要知道接口不能提供什么。接口绝不会有实例字段,在Java8之前,接口中绝对不会实现方法。不过现在已经可以在接口中提供简单方法了。当然,这些方法不能引用实例字段——接口没有实例。
提供实例字段和方法实现的任务应该由实现接口的那个类来完成。因此,可以将接口看成是没有实例字段的抽象类。但是这两个概念还是有一定区别的,稍后将给出详细的解释。
现在,假设希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Comparable接口。
为了让类实现一个接口,需要完成下面的步骤
- 类实现给定的接口
- 对于接口中的所有的方法提供定义
实现接口的语法
class Employee implements Comparable
同时在该情况下,Employee类需要提供 Comparable
中方法
class Employee implements Comparable{ public int compareTo(Object otherObject){ Employee employee = (Employee) otherObject; return Double.compare(salary,other.salary); //其中第一个参数salary调用该方法的字段 如a.compareTo(b),即salary为对象a中的成员属性 } }
下面是需要注意的地方
看完之后你是否会有一个疑问?
原因
代码案例
下面的案例中通过一个实现了 Comparable
接口的 Employee
进行实验。
Employee.java
public class Employee implements Comparable<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 double getSalary(){ return salary; } public void raiseSalary(double byPercent){ double raise = salary*byPercent/100; } @Override public int compareTo(Employee other) { return Double.compare(salary,other.salary); //比较对象中的工资属性 } }
下面是一个测试类,对于上面的 Employee
进行测试
public class EmployeeSortTest { public static void main(String[] args) { Employee[] staff = new Employee[3]; staff[0] = new Employee("Harry Hacker",35000); staff[1] = new Employee("Tony Tester",88000); staff[2] = new Employee("Carl Cracker",75000); Arrays.sort(staff); for(Employee e:staff){ System.out.println("name="+e.getName()+"salary="+e.getSalary()); } } }
运行结果
从运行结果可以看出来,是按员工的工资进行排序的。
如果 Employee
类没有实现 Comparable
接口,将会发生什么
如将 Employee
写成下面这样
package 接口; 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 double getSalary(){ return salary; } public void raiseSalary(double byPercent){ double raise = salary*byPercent/100; } }
当再次运行的时候,将会如预料的那样,抛出一个异常。
总结:,Arrays类的sort()方法是对一个数组进行排序的方法,sort()方法的参数是一个对象数组,也就是要排序的那个数组,但是有些特别的是,这个对象数组中存储的对象的类必须实现了Comparable接口。
Comparable接口是用来比较大小的,要实现这个接口,我们必须重写接口中的CompareTo()方法,这个方法用来比较两个对象的大小,因为方法本身并不知道我我们会根据对象的哪个属性来比较两个对象的大小,因此在这个方法中,我们可以定义我们自己的比较规则。
在上述的代码中,我们调用了Double类的比较方法来比较两个对象的speed属性的大小,如果调用方法的Car对象的speed属性值比方法参数传进来的Car对象的speed值大就返回1,相等就返回0,小于就返回-1。当然,我们也可以自己手写这个部分,无非就是if else判断的事。
其它相关的方法
comparator接口
在comparable接口中已经了解如何对一个对象数组进行排序,前提是对这些对象是实现了Comparable,而且String.compareTo方法可以按字典顺序比较字符串。
现在假设我们希望按长度递增的顺序对字符串进行排序,而不是按字典顺序进行排序。肯定不能让String类用两种不同的方式实现comparaTo方法-----更何况,String类也不应由我们来修改。
要处理这种情况,Arrays.sort方法还有第二个版本,有一个数组和一个比较器(comparator)作为参数,比较器是实现了comparator接口的类的实例。
public interface Comparator<T>{ int compare(T first,T second); }
接口中总结的几句话
思考1?
- 为什么Java的设计者选择不支持多重继承?
其主要原因是多重继承会让语言变得非常的复杂(如同c++),或者效率会降低(如同Eiffel)