1.两种比较接口分析
在“集合框架”中有两种比较接口:Comparable接口和Comparator接口。Comparable是通用的接口,用户可以实现它来完成自己特定的比较,而Comparator可以看成一种算法的实现,在需要容器集合实现比较功能的时候,来指定这个比较器,这可以看成一种设计模式,将算法和数据分离。
前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。
一个类实现了Camparable接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用Sort方法排序了。
而Comparator的作用有两个:
1、如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过Comparator来实现比较算法进行排序;
2、为了使用不同的排序标准做准备,比如:升序、降序或其他什么序。
2 Comparable接口
public interface Comparable { 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 { 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 set = new TreeSet(); 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 map = new TreeMap(); 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 { 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 { 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 { 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 firstNameSet = new TreeSet( 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 lastNameSet = new TreeSet( 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 firstNameMap = new TreeMap( 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 lastNameMap = new TreeMap( 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}
想念我的时候,不要忘记我也在想念你。