1.两种比较接口分析
在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。Comparable是通用的接口,用户可以实现它来完成自己特定的比较,而Comparator可以看成一种算法的实现,在需要容器集合实现比较功能的时候,来指定这个比较器,这可以看成一种设计模式,将算法和数据分离。
前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。
一个类实现了Camparable接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用Sort方法排序了。
而Comparator的作用有两个:
1、如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过Comparator来实现比较算法进行排序;
2、为了使用不同的排序标准做准备,比如:升序、降序或其他什么序。
2 Comparable接口
|
public interface Comparable<T> {
public int compareTo(T o);
}
|
java.lang. Comparable接口定义类的自然顺序,实现该接口的类就可以按这种方式排序。
1)int compareTo(Object o): 比较当前实例对象与对象o,如果位于对象o之前,返回负值,如果两个对象在排序中位置相同,则返回0,如果位于对象o后面,则返回正值。
2)在 Java 2 SDK版本1.4中有二十四个类实现Comparable接口。下表展示了8种基本类型的自然排序。虽然一些类共享同一种自然排序,但只有相互可比的类才能排序。
|
类
|
排序
|
|
BigDecimal,BigInteger,Byte,Double,
Float,Integer,Long,Short
|
按数字大小排序
|
|
Character
|
按 Unicode 值的数字大小排序
|
|
String
|
按字符串中字符
Unicode 值排序
|
利用Comparable接口创建自己的类的排序顺序,只是实现compareTo()方法的问题。通常就是依赖几个数据成员的自然排序。同时类也应该覆盖equals()和hashCode()以确保两个相等的对象返回同一个哈希码。
这个接口的作用:如果数组或者集合中的(类)元素实现了该接口的话,我们就可以调用Collections.sort和Arrays.sort排序,或应用于有序集合TreeSet和TreeMap中。
下面设计一个有序的类Person,它实现Comparable接口,以年龄为第一关键字,姓名为第二关键字升序排序。
Person.java
|
package com.zj.sort.comparable;
public class Person implements Comparable<Person> {
private int age;
private String name;
public Person(int age, String
name) {
this.age = age;
this.name = name;
}
public int compareTo(Person person) {
int cop = age - person.getAge();
if (cop != 0)
return cop;
else
return name.compareTo(person.name);
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
public int hashCode() {
int result = 17;
result = 37 * result + age;
result = 37 * result + name.hashCode();
return result;
}
public boolean equals(Object o) {
if (!(o instanceof Person))
return false;
Person person = (Person) o;
return (age == person.age) && (name.equals(person.name));
}
public String toString() {
return (age + "{" + name + "}");
}
}
|
2.1 测试Arrays.sort()方法
ArraysSortUnit.java
|
package com.zj.sort.comparable;
import java.util.Arrays;
import
com.zj.compare.Person;
public class ArraysSortUnit {
public static void main(String[] args) {
Person[] ps = { new Person(20, "Tom"), new Person(20, "Jeff"),
new Person(30, "Mary"), new Person(20, "Ada"),
new Person(40, "Walton"), new Person(61, "Peter"),
new Person(20, "Bush") };
System.out.println(Arrays.toString(ps));
Arrays.sort(ps);
System.out.println(Arrays.toString(ps));
}
}
|
结果:
[20{Tom}, 20{Jeff}, 30{Mary},
20{Ada},
40{Walton}, 61{Peter}, 20{Bush}]
[20{Ada},
20{Bush}, 20{Jeff}, 20{Tom}, 30{Mary}, 40{Walton}, 61{Peter}]
2.2 测试Collections.sort()方法
CollctionsSortUnit.java
|
package
com.zj.sort.comparable;
import java.util.Arrays;
import
java.util.Collections;
import
com.zj.compare.Person;
public class CollctionsSortUnit {
public static void main(String[] args) {
Person[] ps = { new Person(20, "Tom"), new Person(20, "Jeff"),
new Person(30, "Mary"), new Person(20, "Ada"),
new Person(40, "Walton"), new Person(61, "Peter"),
new Person(20, "Bush") };
System.out.println(Arrays.toString(ps));
Collections.sort(Arrays.asList(ps));
System.out.println(Arrays.toString(ps));
}
}
|
结果:
[20{Tom}, 20{Jeff}, 30{Mary},
20{Ada},
40{Walton}, 61{Peter}, 20{Bush}]
[20{Ada},
20{Bush}, 20{Jeff}, 20{Tom}, 30{Mary}, 40{Walton}, 61{Peter}]
2.3 测试TreeSet
TreeSetUnit.java
|
package com.zj.sort.comparable;
import java.util.TreeSet;
import com.zj.compare.Person;
public class TreeSetUnit {
public static void main(String[] args) {
TreeSet<Person> set = new
TreeSet<Person>();
set.add(new Person(20, "Tom"));
set.add(new Person(20, "Jeff"));
set.add(new Person(30, "Mary"));
set.add(new Person(20, "Ada"));
set.add(new Person(40, "Walton"));
set.add(new Person(61, "Peter"));
set.add(new Person(20, "Bush"));
System.out.println(set);
}
}
|
结果:
[20{Ada},
20{Bush}, 20{Jeff}, 20{Tom}, 30{Mary}, 40{Walton}, 61{Peter}]
2.4 测试TreeMap
TreeMapUnit.java
|
package com.zj.sort.comparable;
import java.util.TreeMap;
import com.zj.compare.Person;
public class TreeMapUnit {
public static void main(String[] args) {
TreeMap<Person, String> map = new
TreeMap<Person, String>();
map.put(new Person(20, "Tom"), "Tom");
map.put(new Person(20, "Jeff"), "Jeff");
map.put(new Person(30, "Mary"), "Mary");
map.put(new Person(20, "Ada"), "Ada");
map.put(new Person(40, "Walton"), "Walton");
map.put(new Person(61, "Peter"), "Peter");
map.put(new Person(20, "Bush"), "Bush");
System.out.println(map);
}
}
|
结果:
{20{Ada}=Ada, 20{Bush}=Bush,
20{Jeff}=Jeff, 20{Tom}=Tom, 30{Mary}=Mary, 40{Walton}=Walton, 61{Peter}=Peter}
3. Comparator接口
|
public interface Comparator<T> {
int compare(T o1, T o2);
boolean equals(Object obj);
}
|
若一个类不能用于实现java.lang.Comparable,或者不喜欢缺省的Comparable行为并想提供自己的排序顺序(可能多种排序方式),你可以实现Comparator接口,从而定义一个比较器。
1)int compare(Object o1, Object o2): 对两个对象o1和o2进行比较,如果o1位于o2的前面,则返回负值,如果在排序顺序中认为o1和o2是相同的,返回0,如果o1位于o2的后面,则返回正值。
2)与Comparable相似,0返回值不表示元素相等。一个0返回值只是表示两个对象排在同一位置。由Comparator用户决定如何处理。
3)boolean equals(Object obj): 指示对象obj是否和比较器相等。该方法覆写Object的equals()方法,检查的是Comparator实现的等同性,不是处于比较状态下的对象。
下面设计一个定义完整equals方法和hashCode方法的类Person。
Person.java
|
package com.zj.sort.comparator;
public class Person {
private String firstName;
private String lastName;
private int age;
public Person(int age, String
firstName, String lastName) {
this.age = age;
this.firstName = firstName;
this.lastName = lastName;
}
public int getAge() {
return age;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public int hashCode() {
int result = 17;
result = 37 * result + age;
result = 37 * result + firstName.hashCode();
result = 37 * result + lastName.hashCode();
return result;
}
public boolean equals(Object o) {
if (!(o instanceof Person))
return false;
Person p = (Person) o;
return (age == p.age) && (firstName.equals(p.firstName))
&& (lastName.equals(p.lastName));
}
public String toString() {
return (age + "{" + firstName + " " + lastName + "}");
}
}
|
下面设计两个比较器。
FirstNameComparator.java
|
package com.zj.sort.comparator;
import java.util.Comparator;
//实现按FirstName |