java lang(Comparable接口) 和java util(Comparator接口)分析比较 Comparator 比较器接口(策略设计模式) Comparable 和 Comparator比较

//Comparable 接口强行对实现它的每个类的对象进行整体排序。 -- 自然排序。类的compareTo称为自然比较方法。

public interface Comparable<T> {
    public int compareTo(T o);
}

  此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法

  实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射(接口 java.util.SortedMap<K,V>)中的键或有序集合(接口 java.util.SortedSet<E>)中的元素,无需指定比较器(接口 java.util.Comparator<T>)。

compareTo 方法的返回值有三种情况:

  1. e1.compareTo(e2) > 0 即 e1 > e2
  2. e1.compareTo(e2) = 0 即 e1 = e2
  3. e1.compareTo(e2) < 0 即 e1 < e2

注意:

1.由于 null 不是一个类,也不是一个对象,因此在重写 compareTo 方法时应该注意 e.compareTo(null) 的情况,即使 e.equals(null) 返回 false,compareTo 方法也应该主动抛出一个空指针异常 NullPointerException。

2.Comparable 实现类重写 compareTo 方法时一般要求 e1.compareTo(e2) == 0 的结果要和 e1.equals(e2) 一致。这样将来使用 SortedSet 等根据类的自然排序进行排序的集合容器时可以保证保存的数据的顺序和想象中一致。

接口实现的例子:

import java.util.ArrayList;
import java.util.Collections;

public class Car implements Comparable<Object>{
	public String name;
	public int price;
	
	public Car(String name, int price){
		this.name = name;
		this.price = price;
	}
	
	public String toString() {
		return this.name + ":" + this.price;
	}
	
	@Override
	public int compareTo(Object o) {
		if ( o instanceof Car) {
			Car  car = (Car)o;
			int result;
			
			result = this.price - car.price;
//			当car的price相同时,比较其name,按String的comparaTo()方法排序
			if (result == 0) {
				result = this.name.compareTo(car.name);
			}
			return result;
		}
		return 0;
	}
	
	public static void main(String[] args) {
		ArrayList<Car> all = new ArrayList<Car>();
		all.add(new Car("兰博基尼", 400));
		all.add(new Car("宝马", 100));
		all.add(new Car("奔驰", 95));
		all.add(new Car("法拉利", 300));
		
		System.out.println(all);
		Collections.sort(all);
		System.out.println(all);
	}

}

打印出:

[兰博基尼:400, 宝马:100, 奔驰:95, 法拉利:300]
[奔驰:95, 宝马:100, 法拉利:300, 兰博基尼:400]

  我们如果需要控制某个类的次序,而该类本身不支持排序(即没有实现Comparable接口);那么可以建立一个该类的比较器来排序,这个比较器只需要实现Comparator接口即可。

public interface Comparator<T> {
     int compare(T o1, T o2);
     boolean equals(Object obj);
}

使用方式主要分三步:

1.创建一个 Comparator 接口的实现类,并赋值给一个对象在 compare 方法中针对自定义类写排序规则

2.将 Comparator 对象作为参数传递给 排序类的某个方法

3.向排序类中添加 compare 方法中使用的自定义类

接口操作例子:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class Car {
	public String name;
	public int price;
	
	public Car(String name, int price){
		this.name = name;
		this.price = price;
	}
	
	public String toString() {
		return this.name + ":" + this.price;
	}
	public static void main(String[] args) {
		ArrayList<Car> all = new ArrayList<Car>();
		all.add(new Car("兰博基尼", 400));
		all.add(new Car("宝马", 100));
		all.add(new Car("奔驰", 95));
		all.add(new Car("法拉利", 300));
		
		System.out.println(all);
		Collections.sort(all, new MyComparator());
		System.out.println(all);	
		
	}

}

class MyComparator implements Comparator<Car> {

	@Override
	public int compare(Car o1, Car o2) {
		// TODO Auto-generated method stub
		int result = o1.price - o2.price;
		if ( result != 0) {
			return result;
		} else {
			return o1.name.compareTo(o2.name);
		}
	}
	
}

打印出:

[兰博基尼:400, 宝马:100, 奔驰:95, 法拉利:300]
[奔驰:95, 宝马:100, 法拉利:300, 兰博基尼:400]

Comparable 和 Comparator比较

Comparable 是排序接口;若一个类实现了 Comparable 接口,就意味着 “该类支持排序”。
而 Comparator 是比较器;我们若需要控制某个类的次序,可以建立一个 “该类的比较器” 来进行排序。

前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于 “静态绑定”,而后者可以 “动态绑定”。

我们不难发现:Comparable 相当于 “内部比较器”,而 Comparator 相当于 “外部比较器”。