简单理解Java中的Comparable接口和Comparator接口

一、Comparable接口

1、Java提供了Comparable接口,其主要作用是用来排序,这个接口中定义了一个 compareTo(Obj obj) 方法,该方法返回了一个整数值,实现该接口的类必须实现重写该方法,然后实现了该接口类的对象就可以比较比大小了。

2、当一个对象调用该方法进行比较时,比如obj1.comparaTo(obj2),如果返回值是0则相等,返回值是正整数则obj1更大,返回值是负整数则obj2更大

3、其中这些类实现了Comparable接口:BigDecimal,Character,Boolean,String,Data,Time等类。

4、那么接下来我们就用TreeSet类举个例子,我们知道TreeSet与HashSet使用hash算法决定储存位置不同,是采用红黑树的数据结构来储存结合元素,并且TreeSet类支持两种排序方法:自然排序定制排序,其中自然排序就可以用来实现Comparable接口。

class T implements Comparable{//我们用T类实现Comparable接口
    int count;//定义一个实例变量
    public T(int count){//包含一个参数的构造器
        this.count = count;}
    @Override//重写toString方法
    public String toString(){
        return "SetMap.T[count:" + count + "]";}
    @Override//重写equal方法
    public boolean equals(Object obj){
        if (this == obj){return true;}
        if (obj != null && obj.getClass() == T.class){
            T t = (T) obj;
            return t.count == this.count;}
        return false;
    }
    @Override//重写compareTo比较方法
    public int compareTo(Object obj) {
        T t = (T)obj;
        return count > t.count ? 1: count < t.count ? -1 : 0;//等同Integer.compare(count, t.count);}}
public class TreeSetTest {
    public static void main(String[] args){
        TreeSet ts = new TreeSet();//自然排序
        T t1 = new T(5);//添加元素
        ts.add(t1);
        T t2 = new T(-3);
        ts.add(t2);
        T t3 = new T(9);
        ts.add(t3);
        T t4 = new T(-2);
        ts.add(t4);
        System.out.println(ts);//输出集合}}

可以看到输出的集合是按我们重写的方法进行顺序排列的,这里多说一句对于TreeSet甚至HashSet尽量不要修改,会导致位置和实际元素不一致。
结果图

再举个例子,我们在二分搜索树或者堆这些数据结构中都会实现这个类,同时会用到泛型的知识。

public class BinarySearchTree<T extends Comparable<T>> {
...//定义变量、构造器、其他函数
    public void insert(T e){//这里举出插入的具体使用方法,因为就是比较数值大小这里不重写方法
        root = insert(root,e);
    }
    public BinaryTreeNode<T> insert(BinaryTreeNode<T> node,T e){
        if (node ==null){//递归基,当递归到某节点的左或右空子树时,新建一个节点插入进来
            size++;
            return new BinaryTreeNode<T>(e);
        }
        if (e.compareTo(node.data)<0){//插入元素与当前节点比较小,则进入左子树
            node.lc = insert(node.lc,e);
        }
        else if (e.compareTo(node.data)>0){//插入元素与当前节点比较大,则进入右子树
            node.rc = insert(node.rc,e);
        }
        else {//出错 
            System.out.println("insert error! ");
        }
        return node;//返回到升一级
    }
}

二、Comparator接口

1、Java提供了Compartor接口,其主要作用也是用来排序,这个接口中定义了一个 int compare(T obj1, T obj2) 方法,该方法返回了一个整数值,实现该接口的类必须实现重写该方法,然后实现了该接口类的对象就可以比较比大小了。

2、当调用该方法时进行比较时,如果返回值是0则相等,返回值是正整数则obj1更大,返回值是负整数则obj2更大

3、Comparator接口是函数式接口,因此建议使用Lambda表达式替代重写方法。

4、那么接下来我们就依旧用TreeSet类举个例子,定制排序就可以用来实现Comparator接口。

class T{//我们创建一个T外部类
    int count;//定义一个实例变量
    public T(int count){//包含一个参数的构造器
        this.count = count;}
    @Override//重写toString方法
    public String toString(){
        return "SetMap.T[count:" + count + "]";}
    @Override//重写equal方法
    public boolean equals(Object obj){
        if (this == obj){return true;}
        if (obj != null && obj.getClass() == T.class){
            T t = (T) obj;
            return t.count == this.count;}
        return false;
    }
public class TreeSetTest {
    public static void main(String[] args){
        TreeSet ts1 = new TreeSet((o1,o2) ->{//定制排序使用lambda表达式实现comparator
            T t5 = (T)o1;//需要强制转换类型
            T t6 = (T)o2;
            return t5.count > t6.count ? -1 : t5.count < t6.count ? 1 : 0; });//同Integer.compare(t5.count, t6.count)
        T t11 = new T(5);//添加元素
        ts1.add(t11);
        T t21 = new T(-3);
        ts1.add(t21);
        T t31 = new T(9);
        ts1.add(t31);
        T t41 = new T(-2);
        ts1.add(t41);
        System.out.println(ts1);

可以看到输出的集合是按我们Lambda方法进行顺序排列的.

在这里插入图片描述

三、总结

Comparable接口,需实现接口和看情况重写方法来使用。而Comparator接口无需实现接口,可以直接Lambda实现函数式接口或者重写。简单情况来说如果是实现一类中大量比较操作建议实现Comparable接口,而只是临时用一下甚至只用一次或是定制规则,建议用Comparator.

你可能感兴趣的:(Java)