一、Comparable接口
Arrays类中的sort方法承诺可以对对象数组进行排序,但要对象所属的类必须实现Comparable接口。
public interface Comparable<T> {
/**
* @param o the object to be compared.
* @return a negative integer, zero, or a positive integer as this object
* is less than, equal to, or greater than the specified object.
*/
public int compareTo(T o);
}
假设希望使用Arrays类的sort方法对Employee对象数组进行排序,Employee类就必须实现Comparable接口
class Employee implements Comparable {
private Integer age;
private Integer salary;//对薪水进行排序
public int compareTo(Object otherObject) {
Employee other = (Employee) otherObject;
//这里使用了静态Double.compare()方法。如果第一个参数小于第二个参数,返回负值
return Double.compare(salary, other.salary);
}
}
总是对Object进行类型转换感觉挺不方便的,可以为泛型Comparable接口提供一个类型参数
class Employee implements Comparable<Employee> {
private Integer age;
private double salary;//对薪水进行排序
public int compareTo(Employee other) {
//Employee other = otherObject;
//这里使用了静态Double.compare()方法。如果第一个参数小于第二个参数,返回负值
return Double.compare(salary, other.salary);
}
}
调用:
Employee[] staff = new Employee[10];
//省略给10个Employee对象赋值
Arrays.sort(staff);
二、Comparator接口
前面已经通过实现了Comparable接口的类的实例。来对一个对象数组进行排序。例如,可以对一个字符串数组排序,因为String类实现了Comparable ,而且String.compareTo方法可以按字典顺序比较字符串。
现在我们希望按长度递增的顺序对字符串进行排序,而不是按字典顺序进行排序。肯定不能让String类用两个不同的方式实现compareTo方法,更何况,String类也不应该由我们修改。
所以,Arrays.sort方法还有第二个版本,有一个数组和一个比较器(Comparator)作为参数,比较器是实现了Comparator接口的类的实例。
public interface Comparator<T> {
/**
* @param o1 the first object to be compared.
* @param o2 the second object to be compared.
* @return a negative integer, zero, or a positive integer as the
* first argument is less than, equal to, or greater than the
* second.
*/
int compare(T o1, T o2);
要按长度比较字符串,可以定义一个实现了Comparator的类
class LengthComparator implements Comparator<String> {
public int compare(String first, String second) {
return first.length() - second.length();
}
}
具体完成比较时,需要建立一个实例:
LengthComparator comp = new LengthComparator();
if (comp.compare(words[i], words[j]) > 0)
...........
将这个比较与words[i].compareTo(words[j])进行比较。这个compare方法要在比较器对象上调用,而不是在字符串本身身上调用。
要对数组排序,需要为Arrays.sort方法传入一个LengthComparator对象:
String[] friends = {"tom", "Mary", "Peter"};
Arrays.sort(friends, new LengthComparator());
完整代码如下:
class LengthComparator implements Comparator<String> {
public int compare(String first, String second) {
return first.length() - second.length();
}
}
public class Test {
public static void main(String[] args) {
String[] friends = {"tom", "Mary", "Peter"};
Arrays.sort(friends, new LengthComparator());
System.out.println(Arrays.toString(friends));
}
}
使用局部内部类改写
public class Test {
//因为main方法是static方法,故将该类加上static修饰
static class LengthComparator implements Comparator<String> {
public int compare(String first, String second) {
return first.length() - second.length();
}
}
public static void main(String[] args) {
String[] friends = {"tom", "Mary", "Peter"};
Arrays.sort(friends, new LengthComparator());
System.out.println(Arrays.toString(friends));
}
}
使用匿名内部类改写
在使用局部内部类时,可以进一步。假设只想创建这个类的一个对象,甚至不需要为类指定名字,这就是匿名内部类。
匿名内部类的语法为:
//SuperType可以使接口,也可以是类
new SuperType(construction parameters) {
inner class methods and data
}
程序为:
public class Test {
public static void main(String[] args) {
String[] friends = {"tom", "Mary", "Peter"};
//这里SuperType是Comparator接口
Arrays.sort(friends, new Comparator<String>() {
public int compare(String first, String second) {
return first.length() - second.length();
}
});
System.out.println(Arrays.toString(friends));
}
}
使用lambda表达式改写
public class Test {
public static void main(String[] args) {
String[] friends = {"tom", "Mary", "Peter"};
Arrays.sort(friends, (first, second) -> {
return first.length() - second.length();
}
);
System.out.println(Arrays.toString(friends));
}
}
这样代码就很简洁了。