Java基础之Comparable与Comparator接口

/ 0评 / 0

前言

今天某客户突然提出一个要求,要将公司某app里面的数据进行下排序,要求先按照类型排序,类型相同的按照文件名排序,想了想,如果自己写排序算法估计又要大半天而且保不准出一个bug直接gg,那估计得被客户吊起来打,所以查了下文档,发现在Collections类与Arrays类中都存在一个void sort(List<T> list)方法,可以直接对List进行升序排列,其中最关键的就是Comparable与Comparator接口,下面就来介绍下这个Java基础知识。

Collections.sort的使用

在介绍Comparable之前首先贴出一段代码介绍下Collections.sort的使用。

public class T {

	public static void main(String[] args) {
		List<Integer> arrays = getIntArray();
		printArray("排序前", arrays);
		Collections.sort(arrays);
		printArray("排序后", arrays);
	}

	public static List<Integer> getIntArray() {
		List<Integer> arrays = new ArrayList<Integer>();
		Random random = new Random();
		for (int i = 0; i < 15; i++) {
			arrays.add(random.nextInt(10));
		}
		return arrays;
	}

	public static <T extends Comparable<? super T>> void printArray(String tag,
			List<T> arrays) {
		System.out.print(tag + ":");
		for (T i : arrays) {
			System.out.print(i.toString());
		}
		System.out.println("");
	}
}
//输出为
//排序前:747456925001945
//排序后:001244455567799

从上面的代码可以看到,仅仅使用了一句Collections.sort(arrays);就将一组数字进行了升序排序,妈妈再也不用担心我纠结使用什么排序算法了。是不是很开心呢?

不过虽然简单一句话就进行了排序,但是万一客户觉得这样排序太没个性了,我需要奇数在前面,偶数在后面,然后分别降序排序,这个时候就该轮到Comparable接口出手了。

Comparable与Comparator

Comparable接口,功能和他的名字一样,仅仅负者比较,就像我们的几大排序算法一样,主要操作就是两两比较,然后互相交换位置而已,所以我们可以自己实现一个Comparable接口,创建我们自己的比较规则,从Collections.sort方法的定义中我们也可以看出,能被sort方法排序的list中的元素都实现了Comparable。

public static <T extends Comparable<? super T>> void sort(List<T> list)

在上面的例子中,Integer类已经实现了Comparable接口,所以可以直接使用sort(List<T> list)方法进行排序,但是对于我们自定义类型如果不实现Comparable接口,那么sort方法则会报错。大部分的Java自带数据类型都实现了Comparable接口。

要想自定义类型也能调用sort方法,或者想改变默认的排序规则,那么有两种方法,一种是调用sort(List<T> list,Comparator<? super T> c)方法,传入一个Comparator接口的实现类另一种就是直接sort(List<T> list),并让自定义类型实现Comparable接口。

 

使用Comparator接口进行排序

首先查看Comparator接口定义。

public interface Comparator<T> {
    /**
     * @param o1 the first object to be compared.
     * @param o2 the second object to be compared.
     * @return 	返回 = 0  表示o1 == o2
		返回 > 0  表示o1 > 02
		返回 < 0  表示o1 < 02
     * @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);

}

下面就使用sort(List<T> list,Comparator<? super T> c)方法来实现上面的问题,要求奇数在偶数前面,并且分别都是升序排列

public class T {

	public static void main(String[] args) {
		List<Integer> arrays = getIntArray();
		printArray("排序前", arrays);
		Collections.sort(arrays, new Comparator<Integer>() {

			@Override
			public int compare(Integer o1, Integer o2) {
				if ((o1 % 2 == 0 && o2 % 2 == 0)
						|| (o1 % 2 == 1 && o2 % 2 == 1)) {
					return o1 - o2;
				}
				return o1 % 2 == 0 ? 1 : -1;
			}
		});
		printArray("排序后", arrays);
	}

	public static List<Integer> getIntArray() {
		List<Integer> arrays = new ArrayList<Integer>();
		Random random = new Random();
		for (int i = 0; i < 15; i++) {
			arrays.add(random.nextInt(10));
		}
		return arrays;
	}

	public static <T extends Comparable<? super T>> void printArray(String tag,
			List<T> arrays) {
		System.out.println(tag + ":");
		for (T i : arrays) {
			System.out.print(i.toString());
		}
		System.out.println("");
	}
}
//输出
//排序前:
//824836845338147
//排序后:
//133357244468888

可以看到,使用了Collections.sort(List<T> list,Comparator<? super T> c)方法,并且Comparator接口的实现为,如果同为奇数偶数则直接比较大小,如果一奇一偶,则返回奇数那个较大。

使用Comparable接口进行排序

同样先查看下Comparable接口的定义。

public interface Comparable<T> {
    /**
     * @param   o the object to be compared.
     * @return 	返回 = 0 表示o1 == o2
		返回 > 0 表示o1 > 02
		返回 < 0 表示o1 < 02
     * @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);
}

下面就使用sort(List<T> lis)方法来实现自定义类型进行排序,要求,先按照年级排序,同年级的按照姓名字母排序

public class T {

    public static void main(String[] args) {
        List<Student> students = new ArrayList<>();
        students.add(new Student(2017, "小白"));
        students.add(new Student(2014, "AAA"));
        students.add(new Student(2013, "小明"));
        students.add(new Student(2014, "ABC"));
        students.add(new Student(2016, "123"));
        students.add(new Student(2016, "!@"));
        students.add(new Student(2013, "阿里"));
        students.add(new Student(2013, "AADB"));
        students.add(new Student(2015, "!@#里"));
        students.add(new Student(2013, "aaa"));
        printArray("排序前", students);
        Collections.sort(students);
        printArray("排序后", students);
    }

    public static <T extends Comparable<? super T>> void printArray(String tag,
            List<T> arrays) {
        System.out.println(tag + ":");
        for (T i : arrays) {
            System.out.print(i.toString());
        }
        System.out.println("");
    }

    public static class Student implements Comparable<Student> {

        // 年级
        public int grade;

        // 姓名
        public String name;

        public Student(int grade, String name) {
            this.grade = grade;
            this.name = name;
        }

        @Override
        public int compareTo(Student other) {
            if (grade == other.grade) {
                return name.compareToIgnoreCase(other.name);
            }
            return grade - other.grade;
        }

        @Override
        public String toString() {
            StringBuffer sb = new StringBuffer();
            sb.append("年级:" + grade);
            sb.append("     name:" + name);
            sb.append("\n");
            return sb.toString();
        }
    }
}

程序输出结果为:

排序前:
年级:2017     name:小白
年级:2014     name:AAA
年级:2013     name:小明
年级:2014     name:ABC
年级:2016     name:123
年级:2016     name:!@
年级:2013     name:阿里
年级:2013     name:AADB
年级:2015     name:!@#里
年级:2013     name:aaa

排序后:
年级:2013     name:aaa
年级:2013     name:AADB
年级:2013     name:小明
年级:2013     name:阿里
年级:2014     name:AAA
年级:2014     name:ABC
年级:2015     name:!@#里
年级:2016     name:!@
年级:2016     name:123
年级:2017     name:小白

发表评论

您的电子邮箱地址不会被公开。