Java中的比较排序collections,comparable,comparator

在集合框架的应用中,往往都要进行排序,排序规则多种多样,或者只是简单的字符串大小排序,简单的数字大小排序,但有时根据需求排序规则会比较复杂。这时就需要收集。排序()的使用技巧了。


对数字大小进行排序(整数):

    public void testSortInteger(){

        List<Integer> list = new ArrayList<Integer>();
        //往list中插入10个100以内的随机整数
        Random random = new Random();
        Integer k;
        for(int i=0;i<10;i++){

            do{//防止重复
                k=random.nextInt(100);//自动装箱,且k在100之内
            }while(list.contains(k));
            list.add(k);
            System.out.println("成功添加整数:"+k);
        }
        System.out.println("-----------排序前------------");
        for(Integer integer:list){
            System.out.println("元素:"+integer);
        }
        Collections.sort(list);//从小到大排序
        System.out.println("-----------排序后------------");
        for(Integer integer:list){
            System.out.println("元素:"+integer);
        }
    }

运行结果: 
成功添加整数:44 
成功添加整数:28 
成功添加整数:18 
成功添加整数:56 
成功添加整数:73 
成功添加整数:84 
成功添加整数:2 
成功添加整数:54 
成功添加整数:65 
成功添加整数:53 
----排序前---- 
元素:44 
元素:28 
元素:18 
元素:56 
元素:73 
元素:84 
元素:2 
元素:54 
元素:65 
元素:53 
----排序后 - --- 
元素:2 
元素:18 
元素:28 
元素:44 
元素:53 
元素:54 
元素:56 
元素:65 
元素:73 
元素:84

结果分析:
。从结果可以看到,对INT的包装类整型了进行到从小大的排序
值得一提的的英文,程序中用了做......而循环排除重复的数字。而内是list.contains(K ),就是一个个遍历元素与比较元素进行equals()方法比较,查看整数的源码可以发现里面重写了equals()方法方法,就是比较拆箱后的值是否相等。


对字符串进行排序(字符串):

public void testSortString(){

        List<String> list = new ArrayList<String>();
        list.add("microsoft");
        list.add("google");
        list.add("Google");
        list.add("h");
        list.add("z");
        System.out.println("-----------排序前------------");
        for(String string:list){
            System.out.println("元素:"+string);
        }
        Collections.sort(list);
        System.out.println("-----------排序后------------");
        for(String string:list){
            System.out.println("元素:"+string);
        }
//      排列顺序:
//      数字:0-9     48---57
//      大写字母:A-Z     65---90
//      小写字母:a-z     97---122
    }

运行结果: 
----排序前---- 
元素:microsoft 
元素:google 
元素:Google 
元素:h 
元素:z 
----排序后---- 
元素:Google 
元素:google 
元素:h 
元素:microsoft 
元素:

结果分析:
对字符串的排序,是一个个字符逐一比较,从小到大,跟字符串长度基本没有关系从运行结果就能看出字符串的排序规则


对普通对象的排序(学生):

    public void testSortStudent(){

        List<Student> list = new ArrayList<Student>();

        Random random = new Random();
        list.add(new Student(random.nextInt(1000)+"","小芳"));
        list.add(new Student(random.nextInt(1000)+"","小明"));
        list.add(new Student(random.nextInt(1000)+"","小红"));
        list.add(new Student(10000+"","哈哈"));
        System.out.println("-----------排序前------------");
        for(Student student:list){
            System.out.println("学生姓名:"+student.name+",学生id:"+student.id);
        }
        Collections.sort(list);
        System.out.println("-----------排序后------------");
        for(Student student:list){
            System.out.println("学生姓名:"+student.name+",学生id:"+student.id);
        }

如果这么写,编译器会报错,报错信息如下:
类型集合中的方法sort(List T)不适用于参数(List Student),意思是sort()方法不适用于对泛型为学生的列表进行排序。为什么会这样呢?在API文档中详细查看对Collection.sort()的描述:
根据指定的比较器引发的顺序排序指定的列表。列表中的所有元素必须使用指定的比较器相互比较(即,c.compare(e1,e2)不得为列表中的任何元素e1和e2引发ClassCastException)。
即sort()方法操作的对象必须实现媲美接口而我们的学生并不是可比接口的实现类,所以报错那为什么上面对整数与字符串的排序就没有报错,来看看两者的源码。:
这里写图片描述

这里写图片描述 
可以看到,String与Integer都实现了Comparable接口。在各自的类定义中都重写了Comparable接口的compareTo()方法:
String的重写compareTo():

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

整型的重写的compareTo():

    public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }
    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

因此,实现了的可比性就是接口默认的比较规则。那我们要实现根据学生ID大小(字符串)对学生进行排序,学生就要实现可比接口并重写的compareTo()方法。


学生。Java

package com.imooc.collection;

import java.util.HashSet;
import java.util.Set;

public class Student implements Comparable<Student> {

    public String id;
    public String name;

    public Set<Course> courses; 
    public Student(String id, String name) {
        super();
        this.id = id;
        this.name = name;
        this.courses = new HashSet<Course>();
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Student other = (Student) obj;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

    @Override
    public int compareTo(Student o) {
        // TODO Auto-generated method stub
        return this.id.compareTo(o.id);//规则:学生**id字符串**从小到大排序
        //==0就是两者相等
        //>0就是前者比后者大
        //<0就是前者比后者小
    }
}

这个编译正常并运行得到运行结果: 
----排序前---- 
学生姓名:小芳,学生id:734 
学生姓名:小明,学生id:292 
学生姓名:小红,学生id:549 
学生姓名:哈哈,学生id:10000 
----排序后---- 
学生姓名:哈哈,学生id:10000 
学生姓名:小明,学生id:292 
学生姓名:小红,学生id:549 
学生姓名:小芳,学生ID:734

结果分析:
根据学生ID(字符串)对学生进行了ID从小到大排序。


如果想根据学生姓名来排列呢?显示可以在重写的compareTo()方法中定义根据学生姓名,而不是学生id的排序规则。下面就介绍Collection.sort()的另一种重载方法:
java .util.Collections.sort(列表列表,比较器c)


新建StudentComparator.java:

package com.imooc.collection;

import java.util.Comparator;

public class StudentComparator implements Comparator<Student> {

    @Override
    public int compare(Student o1, Student o2) {
        // TODO Auto-generated method stub
        return o1.name.compareTo(o2.name);
    }
}

实现比较接口,泛型为学生,重写比较方法,学生根据姓名定义临时排序规则。
运用重载的排序()方法:

public void testSortStudent(){

        List<Student> list = new ArrayList<Student>();

        Random random = new Random();
        list.add(new Student(random.nextInt(1000)+"","Lucy"));
        list.add(new Student(random.nextInt(1000)+"","Jack"));
        list.add(new Student(random.nextInt(1000)+"","Hill"));
        list.add(new Student(10000+"","0abc"));
        System.out.println("-----------排序前------------");
        for(Student student:list){
            System.out.println("学生姓名:"+student.name+",学生id:"+student.id);
        }
        Collections.sort(list);
        System.out.println("-----------排序后------------");
        for(Student student:list){
            System.out.println("学生姓名:"+student.name+",学生id:"+student.id);
        }

        Collections.sort(list, new StudentComparator());
        System.out.println("-----------按照姓名排序后------------");
        for(Student student:list){
            System.out.println("学生姓名:"+student.name+",学生id:"+student.id);
        }
    }

运行结果: 
----排序前---- 
学生姓名:Lucy,学生编号:591 
学生姓名:Jack,学生编号:650 
学生姓名:Hill,学生编号:140 
学生姓名:0abc,学生编号:10000 
- ---排序后----
学生姓名:0abc,学生id:10000 
学生姓名:Hill,学生id:140 
学生姓名:Lucy,学生编号:591 
学生姓名:Jack,学生id:650 
----按照姓名排序后---- 
学生姓名:0abc,学生ID:10000 
学生姓名:希尔,学生ID:140 
学生姓名:杰克,学生ID:650 
学生姓名:露西,学生ID:591

结果分析:
按照姓名排序后的结果运用的是临时的比较器比较器(通过StudentComparator实现)。

posted @ 2017-08-01 22:49  有你晴天  阅读(451)  评论(0)    收藏  举报