zoukankan      html  css  js  c++  java
  • Comparable与Comparator

    • Comparable

      public interface Comparable<T> {
          public int compareTo(T o);
      }
      
    • Comparator

      public interface Comparator<T> {
          int compare(T o1, T o2);
          ...
      }
      
    • 区别与联系
      举栗子:

      • Comparable Demo
        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方法

          //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函数可知:

                  ...
              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类

  • 相关阅读:
    assert函数(python)
    局域网内计算机访问FTP服务器时,提示“无法访问服务器名称或地址
    Win10更新故障修复之路!
    对每个人都有用的人生哲理,值得一看!
    如何定制属于自己的个性化win7主题?
    快来看看我的刷机历程,你有同样的经历么?
    今儿个一起来看看安装系统时关于BIOS的那些事儿
    你是如何在DOS中查看这个电脑的硬盘分区的呢?
    这里有搭建本地服务器的方法合集,一起来看一下吧!
    Windows下快速搭建NodeJS本地服务器
  • 原文地址:https://www.cnblogs.com/libertycode/p/9906581.html
Copyright © 2011-2022 走看看