Comparable與Comparator

  • Comparable
    public interface Comparable<T> { public int compareTo(T o); }
  • Comparator
    public interface Comparator<T> { int compare(T o1, T o2); ... }
  • 區別與聯繫
    舉栗子:
    • Comparable Demojava

      import java.util.*;
      
      public class ComparableDemo {
      
          public static void main(String[] args) {
              List<Person> people=new ArrayList<>();
              people.add(new Person(20,Person.MALE));
              people.add(new Person(22,Person.FEMALE));
              people.add(new Person(21,Person.FEMALE));
              people.add(new Person(24,Person.MALE));
      
              people.sort(null);
      //        Collections.sort(people);
              for (Person person:people) {
                  System.out.println(person);
              }
          }
      
          static class Person
              implements Comparable<Person>
          {
              int age;
              String gender;
              static final String MALE="male";
              static final String FEMALE="female";
              public Person(int age,String gender){
                  this.age=age;
                  this.gender=gender;
              }
      
              @Override
              public String toString() {
                  return "age: "+this.age+", gender: "+this.gender;
              }
      
              @Override
              public int compareTo(Person o) {
                  return this.age-o.age;
              }
          }
      }
      • 類能夠經過實現Comparable接口來擴展排序功能
      • 實現了Comparable的類能夠直接調用list的sort和Collections.sort來實現排序
    • Comparator Demo算法

      import java.util.*;
      
      public class ComparatorDemo {
      
          public static void main(String[] args) {
              List<Person> people=new ArrayList<>();
              people.add(new Person(20,Person.MALE));
              people.add(new Person(22,Person.FEMALE));
              people.add(new Person(21,Person.FEMALE));
              people.add(new Person(24,Person.MALE));
              Comparator<Person> comparator=new Comparator<Person>() {
                  @Override
                  public int compare(Person o1, Person o2) {
                      if (o1==null||o2==null)
                          return 0;
                      return o1.age-o2.age;
                  }
              };
      
              people.sort(comparator);
      //        Collections.sort(people,comparator);
      
              for (Person person:
               people) {
                  System.out.println(person);
              }
          }
      
          static class Person {
              int age;
              String gender;
              static final String MALE="male";
              static final String FEMALE="female";
              public Person(int age,String gender){
                  this.age=age;
                  this.gender=gender;
              }
      
              @Override
              public String toString() {
                  return "age: "+this.age+", gender: "+this.gender;
              }
          }
      }
      • 建立一個實現了Comparator的比較器,也能夠在沒法擴展bean類的時候達到排序的效果
      • Comparator和Comparable的區別就在於Comparable是由自身來實現list排序的邏輯和功能,Compartor則是經過外部來實現list排序的邏輯和功能
    • 從源代碼層面來解析二者的區別:
      • Compartor:
        //先從開始調用的地方開始看: Collections.sort(people);
        轉到Collections的sort源碼:
        //Collections.java public static <T extends Comparable<? super T>> void sort(List<T> list) { list.sort(null); }
        這裏就能看到,其實Collections也是調用了list的sort方法:
        //List.java default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } }
        從第二行能夠看到,調用了Arrays的sort方法ide

        //Arrays.java
        public static <T> void sort(T[] a, Comparator<? super T> c) {
            if (c == null) {
                sort(a);
            } else {
                if (LegacyMergeSort.userRequested)
                    legacyMergeSort(a, c);
                else
                    TimSort.sort(a, 0, a.length, c, null, 0, 0);
            }
        }
        
        public static void sort(Object[] a) {
            if (LegacyMergeSort.userRequested)
                legacyMergeSort(a);
            else
                ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
        }
        
            ...
        
        /** To be removed in a future release. */
        private static void legacyMergeSort(Object[] a) {
            Object[] aux = a.clone();
            mergeSort(aux, a, 0, a.length, 0);
        }
        
        private static void mergeSort(Object[] src,
                                  Object[] dest,
                                  int low,
                                  int high,
                                  int off) {
            int length = high - low;
        
            // Insertion sort on smallest arrays
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                            ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }
        
            ....
        
            // Merge sorted halves (now in src) into dest
            for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
                if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }

        從Arrays的sort方法開始,因爲Compartor爲null,調用只有一個參數Object[] a的sort函數,而後根據預設好的系統參數:LegacyMergeSort.userRequested來判斷調用舊的歸併排序函數仍是調用一個更高性能的歸併排序算法TimSort,這裏只對legacyMergeSort進行分析,由於對於Comparable的調用過程來講基本一致,legacyMergeSort會調用mergeSort函數,在mergeSort函數中能夠看到:函數

        ...
        
                for (int i=low; i<high; i++)
                    for (int j=i; j>low &&
                            ((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
                        swap(dest, j, j-1);
                ...
        會調用實現了Comparable接口的bean類的compareTo方法,所以若是沒有實現Comparable接口的類調用sort(null)函數會拋出錯誤
      • Comparator:代碼基本差很少,在Arrays的sort方法,因爲Compartor不爲null,根據預設好的系統參數:LegacyMergeSort.userRequested來判斷調用舊的歸併排序函數仍是調用一個更高性能的歸併排序算法TimSort,以legacyMergeSort爲入口:性能

        private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                            Comparator<? super T> c) {
            T[] aux = copyOfRange(a, fromIndex, toIndex);
            if (c==null)
                mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
            else
                mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
        }
        
        @SuppressWarnings({"rawtypes", "unchecked"})
        private static void mergeSort(Object[] src,
                                    Object[] dest,
                                    int low, int high, int off,
                                    Comparator c) {
            int length = high - low;
        
            // Insertion sort on smallest arrays
            if (length < INSERTIONSORT_THRESHOLD) {
                for (int i=low; i<high; i++)
                    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
            }
        
            // Recursively sort halves of dest into src
            int destLow  = low;
            int destHigh = high;
            low  += off;
            high += off;
            int mid = (low + high) >>> 1;
            mergeSort(dest, src, low, mid, -off, c);
            mergeSort(dest, src, mid, high, -off, c);
        
            // If list is already sorted, just copy from src to dest.  This is an
            // optimization that results in faster sorts for nearly ordered lists.
            if (c.compare(src[mid-1], src[mid]) <= 0) {
            System.arraycopy(src, low, dest, destLow, length);
            return;
            }
        
            // Merge sorted halves (now in src) into dest
            for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
                if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
                    dest[i] = src[p++];
                else
                    dest[i] = src[q++];
            }
        }

        從帶有Comparator參數的mergeSort函數可知:this

        ...
            for (int i=low; i<high; i++)
                    for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                        swap(dest, j, j-1);
                return;
                ...

        調用了Comparator的compare函數來比較兩個bean類code

相關文章
相關標籤/搜索