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優先排序
public class FirstNameComparator implements Comparator<Person> {
public int compare(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))
return lastName1.compareTo(lastName2);
else
return firstName1.compareTo(firstName2);
}
}
LastNameComparator.java
package com.zj.sort.comparator;
import java.util.Comparator;
//實現按LastName優先排序
public class LastNameComparator implements Comparator<Person> {
public int compare(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))
return firstName1.compareTo(firstName2);
else
return lastName1.compareTo(lastName2);
}
}
下面通過上述兩個比較器,調用Collections.sort和Arrays.sort排序,以及將其應用於有序集合TreeSet和TreeMap中。
3.1 測試Arrays.sort()方法
ArraysSortUnit.java
package com.zj.sort.comparator;
import java.util.Arrays;
public class ArraysSortUnit {
public static void main(String[] args) {
Person[] ps = { new Person(20, "Tom", "A"),
new Person(20, "Jeff", "A"), new Person(30, "Mary", "A"),
new Person(20, "Ada", "B"), new Person(40, "Walton", "B"),
new Person(61, "Peter", "B"), new Person(20, "Bush", "B") };
System.out.println(Arrays.toString(ps));
Arrays.sort(ps,new FirstNameComparator());
System.out.println(Arrays.toString(ps));
Arrays.sort(ps,new LastNameComparator());
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
package com.zj.sort.comparator;
import java.util.Arrays;
import java.util.Collections;
public class CollectionsSortUnit {
public static void main(String[] args) {
Person[] ps = { new Person(20, "Tom", "A"),
new Person(20, "Jeff", "A"), new Person(30, "Mary", "A"),
new Person(20, "Ada", "B"), new Person(40, "Walton", "B"),
new Person(61, "Peter", "B"), new Person(20, "Bush", "B") };
System.out.println(Arrays.toString(ps));
Collections.sort(Arrays.asList(ps),new FirstNameComparator());
System.out.println(Arrays.toString(ps));
Collections.sort(Arrays.asList(ps),new LastNameComparator());
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
package com.zj.sort.comparator;
import java.util.TreeSet;
public class TreeSetUnit {
public static void main(String[] args) {
TreeSet<Person> firstNameSet = new TreeSet<Person>(
new FirstNameComparator());
firstNameSet.add(new Person(20, "Tom", "A"));
firstNameSet.add(new Person(20, "Jeff", "A"));
firstNameSet.add(new Person(30, "Mary", "A"));
firstNameSet.add(new Person(20, "Ada", "B"));
firstNameSet.add(new Person(40, "Walton", "B"));
firstNameSet.add(new Person(61, "Peter", "B"));
firstNameSet.add(new Person(20, "Bush", "B"));
System.out.println(firstNameSet);
TreeSet<Person> lastNameSet = new TreeSet<Person>(
new LastNameComparator());
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
package com.zj.sort.comparator;
import java.util.TreeMap;
public class TreeMapUnit {
public static void main(String[] args) {
TreeMap<Person, String> firstNameMap = new TreeMap<Person, String>(
new FirstNameComparator());
firstNameMap.put(new Person(20, "Tom", "A"), "Tom A");
firstNameMap.put(new Person(20, "Jeff", "A"), "Jeff A");
firstNameMap.put(new Person(30, "Mary", "A"), "Mary A");
firstNameMap.put(new Person(20, "Ada", "B"), "Ada B");
firstNameMap.put(new Person(40, "Walton", "B"), "Walton B");
firstNameMap.put(new Person(61, "Peter", "B"), "Peter B");
firstNameMap.put(new Person(20, "Bush", "B"), "Bush B");
System.out.println(firstNameMap);
TreeMap<Person, String> lastNameMap = new TreeMap<Person, String>(
new LastNameComparator());
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}