比较器(Comparable、Comparator)

本章目标
掌握Comparable比较接口的使用
了解比较器的基本排序原理
掌握Comparator比较接口的使用

 

Comparable接口
可以直接使用java.util.Arrays类进行数组的排序操作,但对象所在的类必须实现Comparable接口,用于指定排序接口,
Comparable接口定义如下:
——public interface Comparable<T>{
public int compareTo(T o) ;
}
——此方法返回一个int类型的数据,但是此int的值只能是以下三种:
————1:表示大于
————-1:表示小于
————0:表示相等

 

定义比较规则,使用Arrays类进行排序

class Student implements Comparable<Student>{//指定泛型类型为 Student
	private String name;
	private int age;
	private float score;
	public Student(String name, int age, float score) {
		this.name = name;
		this.age = age;
		this.score = score;
	}
	public String toString(){
		return name+"\t\t"+age+"\t\t"+score;
	}
	public int compareTo(Student stu){//覆写 compareTo() 方法,实现顺序规则的应用
		if(this.score>stu.score){
			return -1;
		}else if(this.score<stu.score){
			return 1;
		}else{
			if(this.age>stu.age){
				return -1;
			}else if(this.age<stu.age){
				return -1;
			}else{
				return 0;
			}
		}
	}
}
public class ComparableDemo01 {
	public static void main(String[] args) {
		Student stu[] =  {new Student("张三", 20, 90.0f),
			new Student("李四", 22, 90.0f),new Student("王五", 20, 99.0f),
			new Student("赵三", 22, 70.0f),new Student("孙七", 22, 100.0f)	};
		java.util.Arrays.sort(stu);//进行排序操作
		for(int i=0; i<stu.length; i++){//输出数组中的内容
			System.out.println(stu[i]);
		}
	}
/* 结果:
 * 孙七		22		100.0
 * 王五		20		99.0
 * 张三		20		90.0
 * 李四		22		90.0
 * 赵三		22		70.0
 * */
}

 

注意
如果在此时Student类中没有实现Comparable接口,则在执行时会出现以下的异常:
Exception in thread "main" java.lang.ClassCastException:

 

分析比较器的排序原理
实际上之前所讲解的排序过程,也就是经常听到数据结构中的二叉树的排序方法,通过二叉树进行排序,之后利用中序遍历的方式把内容依次读取出来。
二叉树排序的基本原理就是,将第一个内容作为根节点保存,之后如果后面的值比根节点的值小,则放在根节点的左子树,如果后面的值比根节点的值大,则放在根节点的右子树。
比较器(Comparable、Comparator)
 

class BinaryTree{
	class Node{//声明一个节点类
		private Comparable data;//保存具体的内容
		private Node left;//保存左子树
		private Node right;//保存右子树
		public void addNode(Node newNode){
			//要确定是放在左子树还是右子树
			if(newNode.data.compareTo(this.data)<0){
				if(this.left == null){//放在左子树
					this.left = newNode;
				}else{
					this.left.addNode(newNode);
				}
			}
			if(newNode.data.compareTo(this.data)>=0){
				if(this.right == null){//放在右子树
					this.right = newNode;
				}else{
					this.right.addNode(newNode);
				}
			}
		}
		public void printNode(){//输出时采用中序遍历
			if(this.left != null){//先输出左子树
				this.left.printNode();
			}
			System.out.print(this.data + "\t");//再输出根节点
			if(this.right != null){//最后输出右子树
				this.right.printNode();
			}
		}
	};
	private Node root;//根元素
	public void add(Comparable data){
		Node newNode = new Node();//每传入一个新的内容就声明一个根节点
		newNode.data = data;
		if(root == null){
			root = newNode;//如果是第 1 个元素,设置成根元素
		}else{
			root.addNode(newNode);//确定节点是放在左子树还是右子树
		}
	}
	public void print(){//输出节点
		this.root.printNode();
	}
}
public class ComparableDemo03 {
	public static void main(String[] args) {
		BinaryTree bt = new BinaryTree();
		bt.add(8);
		bt.add(3);
		bt.add(3);/*加入重复元素*/
		bt.add(10);
		bt.add(9); 
		bt.add(1);
		bt.add(5);
		bt.add(5); /*加入重复元素*/
		System.out.println("排序之后的结果:");
		bt.print();
	}
/* 结果:
 * 排序之后的结果:
 * 1	3	3	5	5	8	9	10	
 * */
}

 

 Integer为Comparable接口实例化

public class ComparableDemo02 {
	public static void main(String[] args) {
		Comparable com = null;//声明一个 Comparable 接口对象
		com = 30;//通过 Integer 类为 Comparable 实例化
		System.out.println("内容为:"+com);//实际上调用的是 toString() 方法
	}
/* 结果:
 * 内容为:30
 * */
}

 

另一种比较器:Comparator
如果一个类已经开发完成,但是在此类建立的初期并没有实现Comparable接口,此时肯定是无法进行对象排序操作的,所以为了解决这样的问题,java又定义了另一个比较器的操作接口 —— Comparator。此接口定义在java.util包中,接口定义如下:

public interface Comparator<T> {
	public int compare(T o1,T o2) ;
	boolean equals(Object obj) ;
}

 

定义学生类

public class Student {
	private String name ;
	private int age ;
	public Student(String name,int age){
		this.name = name ;
		this.age = age ;
	}
	public boolean equals(Object obj){	// 覆写equals方法
		if(this==obj){
			return true ;
		}
		if(!(obj instanceof Student)){
			return false ;
		}
		Student stu = (Student) obj ;
		if(stu.name.equals(this.name)&&stu.age==this.age){
			return true ;
		}else{
			return false ;
		}
	}
	public void setName(String name){
		this.name = name ;
	}
	public void setAge(int age){
		this.age = age ;
	}
	public String getName(){
		return this.name ;
	}
	public int getAge(){
		return this.age ;
	}
	public String toString(){
		return name + "\t\t" + this.age  ;
	}
}

 

定义比较规则

import java.util.Comparator;
//实现比较器接口
public class StudentComparator implements Comparator<Student> {
	// 为学生类定义比较规则
	public int compare(Student s1,Student s2){
		if(s1.equals(s2)){//如果相等,则返回0
			return 0 ;
		}else if(s1.getAge()<s2.getAge()){	// 按年龄比较
			return 1 ;
		}else{
			return -1 ;
		}
	}
}

 

为对象数组排序

public class ComparatorDemo {
	public static void main(String[] args) {
		Student stu[] = {new Student("张三",20),
				new Student("李四",22),new Student("王五",20),
				new Student("赵六",20),new Student("孙七",22)} ;
			java.util.Arrays.sort(stu,new StudentComparator()) ;	// 进行排序操作
			for(int i=0;i<stu.length;i++){	// 循环输出数组中的内容
				System.out.println(stu[i]) ;
			}
	}
/* 结果:
 * 李四		22
 * 孙七		22
 * 张三		20
 * 王五		20
 * 赵六		20
 * */
}