1.两种比较接口分析
在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。Comparable是通用的接口,用户可以实现它来完成自己特定的比较,而Comparator可以看成一种算法的实现,在需要容器集合实现比较功能的时候,来指定这个比较器,这可以看成一种设计模式,将算法和数据分离。
前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。
一个类实现了Camparable接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用Sort方法排序了。
而Comparator的作用有两个:
1、如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过Comparator来实现比较算法进行排序;
2、为了使用不同的排序标准做准备,比如:升序、降序或其他什么序。
2 Comparable接口
publicinterfaceComparable {
publicintcompareTo(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
packagecom.zj.sort.comparable;
publicclassPersonimplementsComparable {
privateintage;
privateStringname;
publicPerson(intage, String
name) {
this.age= age;
this.name= name;
}
publicintcompareTo(Person person) {
intcop =age- person.getAge();
if(cop != 0)
returncop;
else
returnname.compareTo(person.name);
}
publicintgetAge() {
returnage;
}
publicString getName() {
returnname;
}
publicinthashCode() {
intresult = 17;
result = 37 * result +age;
result = 37 * result +name.hashCode();
returnresult;
}
publicbooleanequals(Object o) {
if(!(oinstanceofPerson))
returnfalse;
Person person = (Person) o;
return(age== person.age) && (name.equals(person.name));
}
publicString toString() {
return(age+"{"+name+"}");
}
}
2.1测试Arrays.sort()方法
ArraysSortUnit.java
packagecom.zj.sort.comparable;
importjava.util.Arrays;
importcom.zj.compare.Person;
publicclassArraysSortUnit {
publicstaticvoidmain(String[] args) {
Person[] ps = {newPerson(20,"Tom"),newPerson(20,"Jeff"),
newPerson(30,"Mary"),newPerson(20,"Ada"),
newPerson(40,"Walton"),newPerson(61,"Peter"),
newPerson(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
packagecom.zj.sort.comparable;
importjava.util.Arrays;
importjava.util.Collections;
importcom.zj.compare.Person;
publicclassCollctionsSortUnit {
publicstaticvoidmain(String[] args) {
Person[] ps = {newPerson(20,"Tom"),newPerson(20,"Jeff"),
newPerson(30,"Mary"),newPerson(20,"Ada"),
newPerson(40,"Walton"),newPerson(61,"Peter"),
newPerson(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
packagecom.zj.sort.comparable;
importjava.util.TreeSet;
importcom.zj.compare.Person;
publicclassTreeSetUnit {
publicstaticvoidmain(String[] args) {
TreeSet set =newTreeSet();
set.add(newPerson(20,"Tom"));
set.add(newPerson(20,"Jeff"));
set.add(newPerson(30,"Mary"));
set.add(newPerson(20,"Ada"));
set.add(newPerson(40,"Walton"));
set.add(newPerson(61,"Peter"));
set.add(newPerson(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
packagecom.zj.sort.comparable;
importjava.util.TreeMap;
importcom.zj.compare.Person;
publicclassTreeMapUnit {
publicstaticvoidmain(String[] args) {
TreeMap map =newTreeMap();
map.put(newPerson(20,"Tom"),"Tom");
map.put(newPerson(20,"Jeff"),"Jeff");
map.put(newPerson(30,"Mary"),"Mary");
map.put(newPerson(20,"Ada"),"Ada");
map.put(newPerson(40,"Walton"),"Walton");
map.put(newPerson(61,"Peter"),"Peter");
map.put(newPerson(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接口
publicinterfaceComparator {
intcompare(T o1, T o2);
booleanequals(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
packagecom.zj.sort.comparator;
publicclassPerson {
privateStringfirstName;
privateStringlastName;
privateintage;
publicPerson(intage, String
firstName, String lastName) {
this.age= age;
this.firstName= firstName;
this.lastName= lastName;
}
publicintgetAge() {
returnage;
}
publicString getFirstName() {
returnfirstName;
}
publicString getLastName() {
returnlastName;
}
publicinthashCode() {
intresult = 17;
result = 37 * result +age;
result = 37 * result +firstName.hashCode();
result = 37 * result +lastName.hashCode();
returnresult;
}
publicbooleanequals(Object o) {
if(!(oinstanceofPerson))
returnfalse;
Person p = (Person) o;
return(age== p.age) && (firstName.equals(p.firstName))
&& (lastName.equals(p.lastName));
}
publicString toString() {
return(age+"{"+firstName+" "+lastName+"}");
}
}
下面设计两个比较器。
FirstNameComparator.java
packagecom.zj.sort.comparator;
importjava.util.Comparator;
//实现按FirstName优先排序
publicclassFirstNameComparatorimplementsComparator {
publicintcompare(Person person, Person
anotherPerson) {
String lastName1 =
person.getLastName().toUpperCase();
String firstName1 =
person.getFirstName().toUpperCase();
String lastName2 =
anotherPerson.getLastName().toUpperCase();
String firstName2 =
anotherPerson.getFirstName().toUpperCase();
if(firstName1.equals(firstName2))
returnlastName1.compareTo(lastName2);
else
returnfirstName1.compareTo(firstName2);
}
}
LastNameComparator.java
packagecom.zj.sort.comparator;
importjava.util.Comparator;
//实现按LastName优先排序
publicclassLastNameComparatorimplementsComparator {
publicintcompare(Person person, Person
anotherPerson) {
String lastName1 =
person.getLastName().toUpperCase();
String firstName1 =
person.getFirstName().toUpperCase();
String lastName2 =
anotherPerson.getLastName().toUpperCase();
String firstName2 =
anotherPerson.getFirstName().toUpperCase();
if(lastName1.equals(lastName2))
returnfirstName1.compareTo(firstName2);
else
returnlastName1.compareTo(lastName2);
}
}
下面通过上述两个比较器,调用Collections.sort和Arrays.sort排序,以及将其应用于有序集合TreeSet和TreeMap中。
3.1测试Arrays.sort()方法
ArraysSortUnit.java
packagecom.zj.sort.comparator;
importjava.util.Arrays;
publicclassArraysSortUnit {
publicstaticvoidmain(String[] args) {
Person[] ps = {newPerson(20,"Tom","A"),
newPerson(20,"Jeff","A"),newPerson(30,"Mary","A"),
newPerson(20,"Ada","B"),newPerson(40,"Walton","B"),
newPerson(61,"Peter","B"),newPerson(20,"Bush","B") };
System.out.println(Arrays.toString(ps));
Arrays.sort(ps,newFirstNameComparator());
System.out.println(Arrays.toString(ps));
Arrays.sort(ps,newLastNameComparator());
System.out.println(Arrays.toString(ps));
}
}
结果:
[20{Tom A}, 20{Jeff A}, 30{Mary
A}, 20{Ada B},
40{Walton B}, 61{Peter B}, 20{Bush B}]
[20{Ada B}, 20{Bush B}, 20{Jeff A}, 30{Mary A},
61{Peter B}, 20{Tom A}, 40{Walton B}]
[20{Jeff A}, 30{Mary A}, 20{Tom
A}, 20{Ada B},
20{Bush B}, 61{Peter B}, 40{Walton B}]
3.2测试Collections.sort()方法
CollctionsSortUnit.java
packagecom.zj.sort.comparator;
importjava.util.Arrays;
importjava.util.Collections;
publicclassCollectionsSortUnit {
publicstaticvoidmain(String[] args) {
Person[] ps = {newPerson(20,"Tom","A"),
newPerson(20,"Jeff","A"),newPerson(30,"Mary","A"),
newPerson(20,"Ada","B"),newPerson(40,"Walton","B"),
newPerson(61,"Peter","B"),newPerson(20,"Bush","B") };
System.out.println(Arrays.toString(ps));
Collections.sort(Arrays.asList(ps),newFirstNameComparator());
System.out.println(Arrays.toString(ps));
Collections.sort(Arrays.asList(ps),newLastNameComparator());
System.out.println(Arrays.toString(ps));
}
}
结果:
[20{Tom A}, 20{Jeff A}, 30{Mary
A}, 20{Ada B},
40{Walton B}, 61{Peter B}, 20{Bush B}]
[20{Ada B}, 20{Bush B}, 20{Jeff A}, 30{Mary A},
61{Peter B}, 20{Tom A}, 40{Walton B}]
[20{Jeff A}, 30{Mary A}, 20{Tom
A}, 20{Ada B},
20{Bush B}, 61{Peter B}, 40{Walton B}]
3.3测试TreeSet
TreeSetUnit.java
packagecom.zj.sort.comparator;
importjava.util.TreeSet;
publicclassTreeSetUnit {
publicstaticvoidmain(String[] args) {
TreeSet firstNameSet =newTreeSet(
newFirstNameComparator());
firstNameSet.add(newPerson(20,"Tom","A"));
firstNameSet.add(newPerson(20,"Jeff","A"));
firstNameSet.add(newPerson(30,"Mary","A"));
firstNameSet.add(newPerson(20,"Ada","B"));
firstNameSet.add(newPerson(40,"Walton","B"));
firstNameSet.add(newPerson(61,"Peter","B"));
firstNameSet.add(newPerson(20,"Bush","B"));
System.out.println(firstNameSet);
TreeSet lastNameSet =newTreeSet(
newLastNameComparator());
lastNameSet.addAll(firstNameSet);
System.out.println(lastNameSet);
}
}
结果:
[20{Ada B}, 20{Bush B}, 20{Jeff A}, 30{Mary A},
61{Peter B}, 20{Tom A}, 40{Walton B}]
[20{Jeff A}, 30{Mary A}, 20{Tom
A}, 20{Ada B},
20{Bush B}, 61{Peter B}, 40{Walton B}]
3.4测试TreeMap
TreeMapUnit.java
packagecom.zj.sort.comparator;
importjava.util.TreeMap;
publicclassTreeMapUnit {
publicstaticvoidmain(String[] args) {
TreeMap
firstNameMap =newTreeMap(
newFirstNameComparator());
firstNameMap.put(newPerson(20,"Tom","A"),"Tom A");
firstNameMap.put(newPerson(20,"Jeff","A"),"Jeff A");
firstNameMap.put(newPerson(30,"Mary","A"),"Mary A");
firstNameMap.put(newPerson(20,"Ada","B"),"Ada
B");
firstNameMap.put(newPerson(40,"Walton","B"),"Walton B");
firstNameMap.put(newPerson(61,"Peter","B"),"Peter B");
firstNameMap.put(newPerson(20,"Bush","B"),"Bush B");
System.out.println(firstNameMap);
TreeMap
lastNameMap =newTreeMap(
newLastNameComparator());
lastNameMap.putAll(firstNameMap);
System.out.println(lastNameMap);
}
}
结果:
{20{Ada
B}=Ada B,
20{Bush B}=Bush B, 20{Jeff A}=Jeff A, 30{Mary A}=Mary A, 61{Peter B}=Peter B,
20{Tom A}=Tom A, 40{Walton B}=Walton B}
{20{Jeff A}=Jeff A, 30{Mary
A}=Mary A, 20{Tom A}=Tom A, 20{Ada B}=Ada B, 20{Bush B}=Bush B,
61{Peter B}=Peter B, 40{Walton B}=Walton B}