Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。

通常对象之间的比较可以从两个方面去看:

第一个方面:对象的地址是否一样,是否引用自同一个对象。这种方式可以直接使用“==“来完成。

第二个方面:以对象的某一个属性的角度去比较,例如以对象的年龄、出生年月、成绩分数、姓氏字母等。

 

从最新的JDK8而言,有三种实现对象比较的方法:

一、覆写Object类的equals()方法,即直接写在类里面;

二、继承Comparable接口,并实现compareTo()方法;

三、定义一个单独的对象比较器,继承自Comparator接口,实现compare()方法

由于使用的排序方式的不同,具体选择哪种方法来实现对象的比较也会有所不同。

 

方式1: 覆写equals()方法

覆写equals()方法,一般用于自己实现对象数组排序的情况,而对于要使用java内置的排序算法时,使用后面两种方式都是可行的。

 

方式2: 继承Comparable接口,并实现 compareTo()方法

这种方式就是让自己编写的类继承Comparable接口,并实现compareTo()方法,这种情况下,在使用java.util.Arrays.sort() 方法时,不用指定具体的比较器,sort()方法会使用对象自己的比较函数来完成对象的排序。

 

方式3:继承自Comparator接口,实现compare()方法

一般使用以上两种方法就能够满足实际的开发问题,但是当出现以下情况时,就需要用到Comparator接口:要在已经开发好的代码的基础上完善对象的比较功能时,又不想更改之前的代码,这种情况下,从JDK1.8之后出现了Comparator接口,是对这种情况的一个弥补。

这种情况下,需要单独定义一个对象比较器,继承Comparator接口,并实现compare()方法。

 

以上三种实现方式的示例代码如下:

package com.mymaven.javademo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

/**
 * @since 	  2017.03.31
 * @author mimvp
 *
 */

class Student {
	private String name;
	private double score;
	
	public Student(String name, double score) {
		this.name = name;
		this.score = score;
	}
	
	public String getName() {
		return this.name;
	}
	
	public double getScore() {
		return this.score;
	}
	
	@Override
	public String toString(){
		return "Student	:	name: " + this.name + "; score: " + this.score;
	}
	
	// 方式1: 覆写equals()方法
	public int equals(Student s) {
		int result = this.score > s.getScore() ? 1 : (this.score < s.getScore() ? -1 : 0);
		if(0 == result) {
			result = this.name.charAt(0) >= s.getName().charAt(0) ? 1 : -1;
		}
		return result;
	}
}

/**
 *  方式2: 继承Comparable接口,并实现 compareTo()方法
 */
@SuppressWarnings("rawtypes")
class Teacher implements Comparable {
	private String name;
	private double score;
	
	public Teacher(String name, double score) {
		this.name = name;
		this.score = score;
	}
	
	public String getName() {
		return this.name;
	}
	
	public double getScore() {
		return this.score;
	}
	
	@Override
	public String toString() {
		return "Teacher	:	name: " + this.name + "; score: " + this.score;
	}
	
	public int compareTo(Object obj) {
		Teacher t = (Teacher) obj;
		int result = this.score > t.score ? 1 : (this.score < t.score ? -1 : 0);
		if(result == 0) {
			result = this.name.indexOf(0) > t.name.indexOf(0) ? 1 : -1;
		}
		return result;
	}
}

/**
 * 方式3: 继承自Comparator接口,实现compare()方法
 */
class StudentComparator implements Comparator<Student> {
	public int compare(Student s1, Student s2) {
		int result = s1.getScore() > s2.getScore() ? 1 : (s1.getScore() < s2.getScore() ? -1 : 0);
		if(0 == result) {
			result = s1.getName().indexOf(0) > s2.getName().indexOf(0) ? 1 : -1;
		}
		return result;
	}
}

/**
 * 主函数
 */
public class JavaDemo {
	@SuppressWarnings("unchecked")
	public static void main(String[] args ) {
		System.out.println("hello world");
		
		// 方式1
		Student s1 = new Student("zzz", 80);
		Student s2 = new Student("bbb", 80);
		System.out.println(s1.getName() + "  >= " + s2.getName() + " : " + s1.equals(s2));
		
		// 方式2
		List<Teacher> teachers = new ArrayList<Teacher>(10);
		teachers.add(new Teacher("ddd", 60));
		teachers.add(new Teacher("aaa", 60));
		teachers.add(new Teacher("bbb", 80));
		teachers.add(new Teacher("ccc", 70));
		Collections.sort(teachers);
		System.out.println(teachers);
		
		// 方式3
		Student[] students = new Student[] {
				new Student("ddd", 60),
				new Student("aaa", 60),
				new Student("bbb", 80),
				new Student("ccc", 70),
		};
		Arrays.sort(students, new StudentComparator());
		System.out.println(Arrays.deepToString(students));
	}
}

运行结果

hello world
zzz  >= bbb : 1
[Teacher	:	name: aaa; score: 60.0, Teacher	:	name: ddd; score: 60.0, Teacher	:	name: ccc; score: 70.0, Teacher	:	name: bbb; score: 80.0]
[Student	:	name: aaa; score: 60.0, Student	:	name: ddd; score: 60.0, Student	:	name: ccc; score: 70.0, Student	:	name: bbb; score: 80.0]

 

 

1. Comparator 和 Comparable 相同的地方

他们都是java的一个接口, 并且是用来对自定义的class类对象的比较大小,什么是自定义class:

public class Person{ String name; int age }

当我们有这么一个personList,里面包含了person1, person2, persion3....., 我们用Collections.sort( personList ), 是得不到预期的结果的. 这时肯定有人要问, 那为什么可以排序一个字符串list呢:

如 StringList{"hello1" , "hello3" , "hello2"}, Collections.sort( stringList ) 能够得到正确的排序, 那是因为 

String 这个对象已经帮我们实现了 Comparable接口 , 所以我们的 Person 如果想排序, 也要实现一个比较器。

 

2. Comparator 和 Comparable 的区别

Comparable

Comparable 定义在 Person类的内部:

public class Persion implements Comparable {..比较Person的大小..}

因为已经实现了比较器,那么我们的Person现在是一个可以比较大小的对象了,它的比较功能和String完全一样,可以随时随地的拿来

比较大小,因为Person现在自身就是有大小之分的。Collections.sort(personList)可以得到正确的结果。

 

Comparator

Comparator 是定义在Person的外部的, 此时我们的Person类的结构不需要有任何变化,如

public class Person{ String name; int age },

然后我们另外定义一个比较器:

public PersonComparator implements Comparator() {..比较Person的大小..}

在PersonComparator里面实现了怎么比较两个Person的大小. 所以,用这种方法,当我们要对一个 personList进行排序的时候, 

我们除了了要传递personList过去, 还需要把PersonComparator传递过去,因为怎么比较Person的大小是在PersonComparator里面实现的, 如:

Collections.sort( personList , new PersonComparator() )

 

 

参考推荐

Java 7种枚举用法

Java 泛型中和 区别

Java 抽象类和接口