在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。像String和Integer等Java内建类实现Comparable接口以提供一定排序方式,但这样只能实现该接口一次。对于那些没有实现Comparable接口的类、或者自定义的类,您可以通过Comparator接口来定义您自己的比较方式。
Comparable接口
在java.lang包中,Comparable接口适用于一个类有自然顺序的时候。假定对象集合是同一类型,该接口允许您把集合排序成自然顺序。
intcompareTo(Object o): 比较当前实例对象与对象o,如果位于对象o之前,返回负值,如果两个对象在排序中位置相同,则返回0,如果位于对象o后面,则返回正值
Comparator接口
若一个类不能用于实现java.lang.Comparable,或者您不喜欢缺省的Comparable行为并想提供自己的排序顺序(可能多种排序方式),你可以实现Comparator接口,从而定义一个比较器。
(1) intcompare(Object o1, Object o2):
对两个对象o1和o2进行比较,如果o1位于o2的前面,则返回负值,如果在排序顺序中认为o1和o2是相同的,返回0,如果o1位于o2的后面,则返回正值
(2) booleanequals(Object obj):
指示对象obj是否和比较器相等
“与Comparable相似,0返回值不表示元素相等。一个0返回值只是表示两个对象排在同一位置。由Comparator用户决定如何处理。如果两个不相等的元素比较的结果为零,您首先应该确信那就是您要的结果,然后记录行为。”
1、自然排序——Comparable
在JDK类库中,有一部分类实现了Comparable接口,如IntegerDouble和String等。Comparable接口有一个comparTo(Objecto)方法,它返回整数类型。对于表达式x.compareTo(y):
如果返回值为0,则表示x和y相等,
如果返回值大于0,则表示x大于y,
如果返回值小于0,则表示x小于y.
TreeSet集合调用对象的compareTo()方法比较集合中的大小,注意不是TreeSet调用它自己的comparTo()方法而是它调用集合中对象的comparTo()方法. TreeSet类本身并没有实现Comparable接口,然后进行升序排列,这种方式称为自然排序.
import java.util.HashSet; import java.util.Set;
publicclass Customer implements Comparable<Object> { private String name;
privateintage;
public Customer(String name, int age) { this.age = age; this.name = name; }
publicint getAge() { returnage; }
publicvoid setAge(int age) { this.age = age; }
public String getName() { returnname; }
publicvoid setName(String name) { this.name = name; }
@Override publicboolean equals(Object obj) { // 重写equals方法 if (this == obj) returntrue; if (!(obj instanceof Customer)) returnfalse; final Customer other = (Customer) obj;
if (this.name.equals(other.getName()) && this.age == other.getAge()) returntrue; else returnfalse; }
publicstaticvoid main(String[] args) { Set<Customer> set = new HashSet<Customer>(); Customer customer1 = new Customer("Tom", 15); Customer customer2 = new Customer("Tom", 15); set.add(customer1); set.add(customer2); System.out.println(set.size()); }
publicint compareTo(Object o) { Customer other = (Customer) o;
// 先按照name属性排序 if (this.name.compareTo(other.getName()) > 0) return 1; if (this.name.compareTo(other.getName()) < 0) return -1;
// 在按照age属性排序 if (this.age > other.getAge()) return 1; if (this.age < other.getAge()) return -1; return 0; }
@Override publicint hashCode() { // 重写equals方法必须重写hashCode方法 int result; result = (name == null ? 0 : name.hashCode()); result = 29 * result + age; return result; } } |
2、客户化排序——Comparable
除了自然排序,TreeSet还支持客户化排序java.util.Comparator<Type>接口提供具体的排序方式,<Type>指定被比较的对象的类型,
Comparator有个compar(Type x,Type y)方法,用于比较两个对象的大小,当compare(x,y)
大于0时表示x大于y,
小于0表示x小于y
等于0表示x等于y
举个例子如果希望TreeSet按照Customer对象的name属性进行降序排列,可以先创建一个实现Comparator接口的类
import java.util.Comparator; import java.util.Iterator; import java.util.Set; import java.util.TreeSet;
publicclass CustomerComparator implements Comparator<Customer>{
publicint compare(Customer c1, Customer c2) { if(c1.getName().compareTo(c2.getName())>0)return -1; if(c1.getName().compareTo(c2.getName())<0)return 1;
return 0; }
publicstaticvoid main(String args[]){ Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
Customer customer1= new Customer("Tom",15); Customer customer3= new Customer("Jack",16); Customer customer2= new Customer("Mike",26); set.add(customer1); set.add(customer2); set.add(customer3);
Iterator<Customer> it = set.iterator(); while(it.hasNext()){ Customer customer = it.next(); System.out.println(customer.getName()+" "+customer.getAge()); } } } |
3、Comparable接口和Comparator接口的区别
用自定义类实现Comparable接口,那么这个类就具有排序功能,Comparable和具体你要进行排序的类的实例邦定。
而Comparator比较灵活,只需要通过构造方法指定一个比较器就行了实现它的自定义类仅仅定义了一种排序方式或排序规则。不言而喻,这种方式比较灵活。我们的要排序的类可以分别和多个实现Comparator接口的类绑定,从而达到可以按自己的意愿实现按多种方式排序的目的。
Comparable——“静态绑定排序”,Comparator——“动态绑定排序”。
Comparator接口和具体的实现类,是策略模式的体现,Comparator定义了策略类共同需要实现的接口,而具体策略类实现了具体的比较算法。