JAVA比较器排序及对比自然排序

二、比较器排序:java.util.Comparator
  上篇博客(自然排序)我提到了之所以提供比较器排序接口,是因为有时需要对同一对象进行多种不同方式的排序,这点自然排序 Comparable 不能实现。另外, Comparator 接口的一个好处是将比较排序算法和具体的实体类分离了。
  翻翻 API 会发现, Arrays.sort 还有种重载形式:sort(T[] a, Comparator<? super T> c) ,这个方法参数的写法用到了泛型,我们还没讲到。我们可以把它理解成这样的形式: sort(Object[] a, Comparator c) ,这个方法的意思是按照比较器 c 给出的比较排序算法,对 Object 数组进行排序。Comparator 接口中定义了两个方法: compare(Object o1, Object o2) 和 equals 方法,由于 equals 方法所有对象都有的方法,因此当我们实现 Comparator 接口时,我们只需重写 compare 方法,而不需重写 equals 方法。Comparator 接口中对重写 equals 方法的描述是:“注意,不重写 Object.equals(Object) 方法总是安全的。然而,在某些情况下,重写此方法可以允许程序确定两个不同的 Comparator 是否强行实施了相同的排序,从而提高性能。”。我们只需知道第一句话就OK了,也就是说,可以不用去想应该怎么实现 equals 方法,因为即使我们不显示实现 equals 方法,而是使用Object类的 equals 方法,代码依然是安全的。而对于第二句话,究竟是怎么提高比较器性能的,我也不了解,所以就不说了。
  那么我们来写个代码,来用一用比较器排序。还是用 Student 类来做,只是没有实现 Comparable 接口。由于比较器的实现类只用显示实现一个方法,因此,我们可以不用专门写一个类来实现它,当我们需要用到比较器时,可以写个匿名内部类来实现 Comparator 。下面是我们的按姓名排序的方法:
  

public void sortByName () {  
    Student stu1 = new Student(1, "Little");  
    Student stu2 = new Student(2, "Cyntin");  
    Student stu3 = new Student(3, "Tony");  
    Student stu4 = new Student(4, "Gemini");  

    Student[] stus = new Student[4];  
    stus[0] = stu1;  
    stus[1] = stu4;  
    stus[2] = stu3;  
    stus[3] = stu2;  
    System.out.println("Array: " + Arrays.toString(stus));  

    Arrays.sort(stus, new Comparator() {  

        @Override  
        public int compare(Object o1, Object o2) {  
            if (o1 instanceof Student && o2 instanceof Student) {  
                Student s1 = (Student) o1;  
                Student s2 = (Student) o2;  
                //return s1.getId() - s2.getId(); // 按Id排  
                return s1.getName().compareTo(s2.getName()); // 按姓名排  
            }  
            return 0;  
        }  

    });  

    System.out.println("Sorted: " + Arrays.toString(stus));  
}  

当我们需要对Student按学号排序时,只需修改我们的排序方法中实现Comparator的内部类中的代码,而不用修改 Student 类。

P.S. 当然,你也可以用 Student 类实现 Comparator 接口,这样Student就是(is a)比较器了(Comparator)。当需要使用这种排序的时候,将 Student 看作 Comparator 来使用就可以了,可以将 Student 作为参数传入 sort 方法,因为 Student is a Comparator 。但这样的代码不是个优秀的代码,因为我们之所以使用比较器(Comparator),其中有个重要的原因就是这样可以把比较算法和具体类分离,降低类之间的耦合。

当Java构造器排序和自然排序同时出现时,默认选择比较器排序.

下面,分别给出使用两种排序比较方式的 TreeSet 测试代码:


/** 
 * 使用自然排序 
 * Student必须实现Comparable接口,否则会抛出ClassCastException 
 */  
public void testSortedSet3() {  
    Student stu1 = new Student(1, "Little");  
    Student stu2 = new Student(2, "Cyntin");  
    Student stu3 = new Student(3, "Tony");  
    Student stu4 = new Student(4, "Gemini");  

    SortedSet set = new TreeSet();  
    set.add(stu1);  
    set.add(stu3); // 若Student没有实现Comparable接口,抛出ClassCastException  
    set.add(stu4);  
    set.add(stu2);  
    set.add(stu4);  
    set.add(new Student(12, "Little"));  

    System.out.println(set);  
}  
/** 
 * 使用比较器排序 
 * Student可以只是个简单的Java类,不用实现Comparable接口 
 */  
public void testSortedSet3() {  
    Student stu1 = new Student(1, "Little");  
    Student stu2 = new Student(2, "Cyntin");  
    Student stu3 = new Student(3, "Tony");  
    Student stu4 = new Student(4, "Gemini");  

    SortedSet set = new TreeSet(new Comparator() {  

        @Override  
        public int compare(Object o1, Object o2) {  
            if (o1 instanceof Student  
                    && o2 instanceof Student) {  
                Student s1 = (Student) o1;  
                Student s2 = (Student) o2;  
                return s1.getName().compareTo(s2.getName());  
            }  
            return 0;  
        }  

    });  

    set.add(stu1);  
    set.add(stu3);  
    set.add(stu4);  
    set.add(stu2);  
    set.add(stu4);  
    set.add(new Student(12, "Little"));  

    System.out.println(set);  
}  

最后,介绍个工具类,java.util.Collections。注意,这不是Collection接口。Collections很像Arrays类。Arrays提供了一系列用于对数组操作的静态方法,查找排序等等。Collections也提供了一系列这样的方法,只是它是用于处理集合的,虽然Collections类和Collection接口很像,但是不要被Collections的名字给欺骗了,它不是只能处理Collection接口以及子接口的实现类,同样也可以处理Map接口的实现类。

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值