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

    Comparable

    包名:java.lang

    public interface Comparable<T> {
        /**
         * Compares this object with the specified object for order.  Returns a
         * negative integer, zero, or a positive integer as this object is less
         * than, equal to, or greater than the specified object.
         *
         * <p>The implementor must ensure <tt>sgn(x.compareTo(y)) ==
         * -sgn(y.compareTo(x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
         * implies that <tt>x.compareTo(y)</tt> must throw an exception iff
         * <tt>y.compareTo(x)</tt> throws an exception.)
         *
         * <p>The implementor must also ensure that the relation is transitive:
         * <tt>(x.compareTo(y)&gt;0 &amp;&amp; y.compareTo(z)&gt;0)</tt> implies
         * <tt>x.compareTo(z)&gt;0</tt>.
         *
         * <p>Finally, the implementor must ensure that <tt>x.compareTo(y)==0</tt>
         * implies that <tt>sgn(x.compareTo(z)) == sgn(y.compareTo(z))</tt>, for
         * all <tt>z</tt>.
         *
         * <p>It is strongly recommended, but <i>not</i> strictly required that
         * <tt>(x.compareTo(y)==0) == (x.equals(y))</tt>.  Generally speaking, any
         * class that implements the <tt>Comparable</tt> interface and violates
         * this condition should clearly indicate this fact.  The recommended
         * language is "Note: this class has a natural ordering that is
         * inconsistent with equals."
         *
         * <p>In the foregoing description, the notation
         * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
         * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
         * <tt>0</tt>, or <tt>1</tt> according to whether the value of
         * <i>expression</i> is negative, zero or positive.
         *
         * @param   o the object to be compared.
         * @return  a negative integer, zero, or a positive integer as this object
         *          is less than, equal to, or greater than the specified object.
         *
         * @throws NullPointerException if the specified object is null
         * @throws ClassCastException if the specified object's type prevents it
         *         from being compared to this object.
         */
        public int compareTo(T o);
    }
    View Code

    从源码compareTo(T o)中可以看出Comparable是一个内比较器,实现Comparable接口的类,都可以与自身比较,至于和另一个实现了Comparable接口的类如何比较,则依赖compareTo方法实现,compareTo方法也被称为自然比较法。如果开发者add进入一个Collection的对象想要Collections的sort方法帮你自动进行排序的话,那么这个对象必须实现Comparable接口。compareTo方法的返回值是int,有三种情况:

    • 比较者大于被比较者(也就是compareTo方法里面的对象),那么返回正整数
    • 比较者等于被比较者,那么返回0
    • 比较者小于被比较者,那么返回负整数

    示例

     1 public class Student implements Comparable<Student >
     2 {
     3     private String name;
     4 
     5     public Student (String name)
     6     {
     7         this.name= name;
     8     }
     9 
    10     public int compareTo(Student stu)
    11     {
    12         if (this.name.compareTo(stu.str) > 0)
    13             return 1;
    14         else if (this.name.compareTo(domain.name) == 0)
    15             return 0;
    16         else 
    17             return -1;
    18     }
    19     
    20     public String getName()
    21     {
    22         return name;
    23     }
    24 }
    View Code

    调用

    public static void main(String[] args)
        {
            Student stu1 = new Student ("c");
            Student stu2 = new Student ("c");
            Student stu3 = new Student ("b");
            Student stu4 = new Student ("d");
            System.out.println(stu1.compareTo(stu2));
            System.out.println(stu1.compareTo(stu3));
            System.out.println(stu1.compareTo(stu4));
        }

    注意: 前面说实现Comparable接口的类是可以支持和自己比较的,但是其实代码里面Comparable的泛型未必就一定要是Domain,将泛型指定为String或者指定为其他任何任何类型都可以----只要开发者指定了具体的比较算法就行。

    Conparator

    包名:java.util

    @FunctionalInterface
    public interface Comparator<T> {
        /**
         * Compares its two arguments for order.  Returns a negative integer,
         * zero, or a positive integer as the first argument is less than, equal
         * to, or greater than the second.<p>
         *
         * In the foregoing description, the notation
         * <tt>sgn(</tt><i>expression</i><tt>)</tt> designates the mathematical
         * <i>signum</i> function, which is defined to return one of <tt>-1</tt>,
         * <tt>0</tt>, or <tt>1</tt> according to whether the value of
         * <i>expression</i> is negative, zero or positive.<p>
         *
         * The implementor must ensure that <tt>sgn(compare(x, y)) ==
         * -sgn(compare(y, x))</tt> for all <tt>x</tt> and <tt>y</tt>.  (This
         * implies that <tt>compare(x, y)</tt> must throw an exception if and only
         * if <tt>compare(y, x)</tt> throws an exception.)<p>
         *
         * The implementor must also ensure that the relation is transitive:
         * <tt>((compare(x, y)&gt;0) &amp;&amp; (compare(y, z)&gt;0))</tt> implies
         * <tt>compare(x, z)&gt;0</tt>.<p>
         *
         * Finally, the implementor must ensure that <tt>compare(x, y)==0</tt>
         * implies that <tt>sgn(compare(x, z))==sgn(compare(y, z))</tt> for all
         * <tt>z</tt>.<p>
         *
         * It is generally the case, but <i>not</i> strictly required that
         * <tt>(compare(x, y)==0) == (x.equals(y))</tt>.  Generally speaking,
         * any comparator that violates this condition should clearly indicate
         * this fact.  The recommended language is "Note: this comparator
         * imposes orderings that are inconsistent with equals."
         *
         * @param o1 the first object to be compared.
         * @param o2 the second object to be compared.
         * @return a negative integer, zero, or a positive integer as the
         *         first argument is less than, equal to, or greater than the
         *         second.
         * @throws NullPointerException if an argument is null and this
         *         comparator does not permit null arguments
         * @throws ClassCastException if the arguments' types prevent them from
         *         being compared by this comparator.
         */
        int compare(T o1, T o2);
    
        /**
         * Indicates whether some other object is &quot;equal to&quot; this
         * comparator.  This method must obey the general contract of
         * {@link Object#equals(Object)}.  Additionally, this method can return
         * <tt>true</tt> <i>only</i> if the specified object is also a comparator
         * and it imposes the same ordering as this comparator.  Thus,
         * <code>comp1.equals(comp2)</code> implies that <tt>sgn(comp1.compare(o1,
         * o2))==sgn(comp2.compare(o1, o2))</tt> for every object reference
         * <tt>o1</tt> and <tt>o2</tt>.<p>
         *
         * Note that it is <i>always</i> safe <i>not</i> to override
         * <tt>Object.equals(Object)</tt>.  However, overriding this method may,
         * in some cases, improve performance by allowing programs to determine
         * that two distinct comparators impose the same order.
         *
         * @param   obj   the reference object with which to compare.
         * @return  <code>true</code> only if the specified object is also
         *          a comparator and it imposes the same ordering as this
         *          comparator.
         * @see Object#equals(Object)
         * @see Object#hashCode()
         */
        boolean equals(Object obj);
    
      //其他再次不列出
    }
    View Code

    从方法compare(T o1, T o2)可以看出Comparator是一个外比较器,有两种场景可能需要实现Comparator接口:

    • 一个对象不支持自己和自己比较(没有实现Comparable接口),但是又想对两个对象进行比较;
    • 一个对象实现了Comparable接口,但是开发者认为compareTo方法中的比较方式并不是自己想要的那种比较方式.

    Comparator接口里面有一个compare方法,方法有两个参数T o1和T o2,是泛型的表示方式,分别表示待比较的两个对象,方法返回值和Comparable接口一样是int,有三种情况:

    • o1大于o2,返回正整数;
    • o1等于o2,返回0;
    • o1小于o3,返回负整数.

    写个很简单的例子,上面代码的Student不变(假设这就是第2种场景,我对这个compareTo算法实现不满意,要自己写实现):

     1 public class StudentComparator implements Comparator<Student>
     2 {
     3     public int compare(Student stu1, Student stu2)
     4     {
     5         if (stu1.getName().compareTo(stu2.getName()) > 0)
     6             return 1;
     7         else if (stu2.getName().compareTo(stu2.getName()) == 0)
     8             return 0;
     9         else 
    10             return -1;
    11     }
    12 }
    View Code

    调用示例:

    public static void main(String[] args)
    {
        Student s1 = new Student("c");
        Student s2 = new Student("c");
        Student s3 = new Student("b");
        Student s4 = new Student("d");
        StudentComparator sc = new StudentComparator();
        System.out.println(sc.compare(s1, s2));
        System.out.println(sc.compare(s1, s3));
        System.out.println(sc.compare(s1, s4));
    }

    当然因为泛型已指定,所以实现Comparator接口的实现类只能是两个相同的对象(不能一个Domain、一个String)进行比较了,因此实现Comparator接口的实现类一般都会以"待比较的实体类+Comparator"来命名

    从Conparable和Comparator的示例可以看出:

    • 如果实现类没有实现Comparable接口,又想对两个类进行比较(或者实现类实现了Comparable接口,但是对compareTo方法内的比较算法不满意),那么可以实现Comparator接口,自定义一个比较器,写比较算法
    • 实现Comparable接口的方式比实现Comparator接口的耦合性要强一些,如果要修改比较算法,要修改Comparable接口的实现类,而实现Comparator的类是在外部进行比较的,不需要对实现类有任何修改。从这个角度说,其实有些不太好,尤其在我们将实现类的.class文件打成一个.jar文件提供给开发者使用的时候。实际上实现Comparator接口的方式后面会写到就是一种典型的策略模式
  • 相关阅读:
    relative 和 absolute 定位关系
    基于Linux的Samba开源共享解决方案测试(四)
    基于Linux的Samba开源共享解决方案测试(三)
    基于Linux的Samba开源共享解决方案测试(二)
    基于Linux的Samba开源共享解决方案测试(一)
    创建文件测试
    RHEL6.x查看网卡槽位对应设备文件及路径
    linux I/O优化 磁盘读写参数设置
    20个Linux服务器性能调优技巧
    Linux文件读写机制及优化方式
  • 原文地址:https://www.cnblogs.com/dudu2mama/p/14150984.html
Copyright © 2011-2022 走看看