栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Comparetor与Comparable

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Comparetor与Comparable

Comparable

Comparable接口中的compareTo方法用于实现一些类中的数据排序功能,例如ArrayList,Arrays,TreeSet等类。其中Arrays类需要主动调用sort,之后sort方法将会调用重载好的compareTo方法作为排序规则,之后该类内的数据便会以排序后的数据进行存放,而TreeSet作为一种本身有序的方法,会默认调用compareTo方法来排序。

早期
public interface Comparable
{
int compareTo(Object other)
}
java5版本之后的Comparable接口已经将Comparable接口提升为了一个泛型类型
public interface Comparable
{
int compareTo(T other)
}
因此在实现Comparable的接口的类中,必须提供以下方法
int compareTo(T other)
当然也仍旧可以使用早期的Object参数版本,但是如果使用这种方法必须使用强制类型转换,这也就增加了ClassCastException出现的可能性

一、基本使用

以以下这道例题来作为假设:
(1)定义User类(sno,name,password,birthDate,sex,salary)。
(2)要求重写toString()方法和compareTo()方法,用户先按sex再按birthDate排序。
(3)至少生成5个User对象,放入到ArrayList中,并排序输出。

现在, 假设希望使用 ArrayList 类的 sort 方法对 User 对象数组进行排序, User类
就必须实现 Comparable 接口。
为了让类实现一个接口, 通常需要下面两个步骤:
1 ) 将类声明为实现给定的接口。
2 ) 对接口中的所有方法进行定义。
要将类声明为实现某个接口, 需要使用关键字 implements:
class User iipleients Comparable
当然, 这里的 User 类需要提供 compareTo 方法。

import java.io.*;
import java.util.ArrayList;

public class User implements Comparable { //注意,再java5中,comparable接口已经提升为一个泛型类型
    public int sno;
    public String name;
    public String password;
    public String birthDate;
    public String sex; //male female
    public double salary;

    @Override
    public String toString() {
        return "sno=" + sno + "  name=" + name + "  password=" + password + "  birthdate=" + birthDate + "  sex=" + sex + "  salary=" + salary;
    }
    @Override
    public int compareTo(User user){
       if(this.sex.compareTo(user.sex)<0){  //说明此时是女的和男的比
           return -1;  //这里调用的是String类型的compareTo
       }		//还有Double.compareTo等等类型比较
       else if(this.sex.compareTo(user.sex)==0){  //女的和女的或男的和男的
           if(this.sex.compareTo("female")==0){
               return this.birthDate.compareTo(user.birthDate);
           }//此时是女生与女生比,让生日小的再前面,大的在后面
           else{
               return this.birthDate.compareTo(user.birthDate);
           }
       }
       else if(this.sex.compareTo(user.sex)>0){//此处说明是男的和女的比
           return 1; //让男的再后面
       }
        return 0;
    }
    public User() {
    }

    public User(String name, String password, String birthDate, String sex, double salary,int sno) {
        this.sno = sno;
        this.name = name;
        this.password = password;
        this.birthDate = birthDate;
        this.sex = sex;
        this.salary = salary;
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ArrayListarrayList=new ArrayList();
        arrayList.add(new User("zjb","1","0114","male",123.2,1));
        arrayList.add(new User("hyl","2","0625","female",123.2,2));
        arrayList.add(new User("zb","3","0707","male",123.2,3));
        arrayList.add(new User("yl","4","0617","female",123.2,4));
        arrayList.add(new User("love","5","0520","female",123.2,5));
        arrayList.sort(User::compareTo);
        for(int i=0;i<5;i++)
        {
            System.out.println(arrayList.get(i));
        }
}

运行结果如下,在main函数中显式调用sort并且放入我们从写好的compareTo方法对ArrayList类对象进行排序。
compareTo返回值一般为-1,0,1,以及如果两个对象无法比较,那么会抛出异常,且返回值为-1的放在上面,为1的在下面,也就是按照升序排序。

接下来是一些可能出现的问题以及可能出现的疑惑的解答

语 言 标 准 规 定:对 于 任 意 的 x 和 y, 实 现 必 须 能 够 保 证 sgn(x.compareTo(y)) = -sgn
(y.compareTo(x)。) (也 就 是 说, 如 果 y.compareTo(x) 抛 出 一 个 异 常, 那 么 x.compareTo(y) 也 应 该 抛 出 一 个 异 常。)这 里 的“ sgn” 是 一 个 数 值 的 符 号:如 果 n 是 负 值, sgn(n) 等 于 -1 ; 如 果 n 是 0, sgn(n) 等 于 0 ; 如 果 n 是 正 值, sgn(n)等 于 1 简 单 地 讲, 如 果 调 换compareTo 的 参 数, 结 果 的 符 号 也 应 该 调 换 (而 不 是 实 际 值) 与 equals 方 法 一 样, 在 继 承 过 程 中 有 可 能 会 出 现 问 题。
例如由于父类实现了Comparable,而子类并没有,那么我们并不能按照比较父类对象的方法来比较子类,这是由于我们不可能强制的将子类对象转换为父类对象,这有可能出现异常。
如 果 子 类 之 间 的 比 较 含 义 不 一 样, 那 就 属 于 不 同 类 对 象 的 非 法 比 较。因此, 每 个compareTo 方 法 都 应 该 在 开 始 时 进 行 下 列 检 测:
if (getClassO != other.getClassO) throw new ClassCastExceptionO;
如 果 存 在 这 样 一 种 通 用 算 法, 它 能 够 对 两 个 不 同 的 子 类 对 象 进 行 比 较, 则 应 该 在 超类 中 提 供 一 个 compareTo 方 法,并 将 这 个 方 法 声 明 为 final 。

对于Arrays类中的sort方法,其中可能的实现过程如下

if(a[i].compareTo(a[j])>0)
{
		//rerange
}

也就是编译器必须确认a[i]一定有一个方法compareTo,因此如果a是一个Comparable对象的数组,就可以确保拥有compareTo方法,因为每个实现Comparable接口的类都必须提供这个方法的定义。

又人认为,将Arrays类中的sort方法定义为接收一个Comparable[ ]数组,倘若有人调用sort方法时所提供的数组元素类型没有实现Comparable方法,编译器就会给出错误报告。但事实并非如此。在这种情况下,sort方法可以接收一个 Object[ ]数组,并对其进行笨拙的类型转换:
// Approach used in the standard library–not recommendedif (((Comparable) a[i]).compareTo(a[j])>0)
{
l/rearrange a[i] and alj]
如果a[i]不属于实现了Comparable接口的类,那么虚拟机就会抛出一个异常。

Comparator

Comparator一般用于我们不能使用compareTo方法来比较两个对象的时候,例如compareTo默认比较的是两个String对象中所在字典的先后有顺序,那么如果我们需要比较的是字符串的长度,我们就需要将String类的compareTo方法重载为比较两个字符串的长度,那么这种出现两种compareTo的情况我们应该避免,因此Java提供了Comparator(比较器)接口。

public interface Comparator
{
int compare(T o1,T o2)
}

package Learning.InterfaceDemo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

public class ComparatorDemo implements Comparator { //注意,再java5中,comparable接口已经提升为一个泛型类型
    public int sno;
    public String name;
    public String password;
    public String birthDate;
    public String sex; //male female
    public double salary;

    @Override
    public String toString() {
        return "sno=" + sno + "  name=" + name + "  password=" + password + "  birthdate=" + birthDate + "  sex=" + sex + "  salary=" + salary;
    }

    @Override
    public int compare(ComparatorDemo user1, ComparatorDemo user2) {
        if (user1.sex.compareTo(user2.sex) < 0) {  //说明此时是女的和男的比
            return -1;  //这里调用的是String类型的compareTo
        }        //还有Double.compareTo等等类型比较
        else if (user1.sex.compareTo(user2.sex) == 0) {  //女的和女的或男的和男的
            if (user1.sex.compareTo("female") == 0) {
                return user1.birthDate.compareTo(user2.birthDate);
            }//此时是女生与女生比,让生日小的再前面,大的在后面
            else {
                return user1.birthDate.compareTo(user2.birthDate);
            }
        } else if (user1.sex.compareTo(user2.sex) > 0) {//此处说明是男的和女的比
            return 1; //让男的再后面
        }
        return 0;
    }

    public ComparatorDemo() {
    }

    public ComparatorDemo(String name, String password, String birthDate, String sex, double salary, int sno) {
        this.sno = sno;
        this.name = name;
        this.password = password;
        this.birthDate = birthDate;
        this.sex = sex;
        this.salary = salary;
    }

    public static void main(String[] args) throws IOException, ClassNotFoundException {
        ArrayList arrayList = new ArrayList<>();
        arrayList.add(new ComparatorDemo("zjb", "1", "0114", "male", 123.2, 1));
        arrayList.add(new ComparatorDemo("hyl", "2", "0625", "female", 123.2, 2));
        arrayList.add(new ComparatorDemo("zb", "3", "0707", "male", 123.2, 3));
        arrayList.add(new ComparatorDemo("yl", "4", "0617", "female", 123.2, 4));
        arrayList.add(new ComparatorDemo("love", "5", "0520", "female", 123.2, 5));
        Collections.sort(arrayList, new ComparatorDemo());
        for (int i = 0; i < 5; i++) {
            System.out.println(arrayList.get(i));
        }
    }
}

与Comparable接口类似,Comparator接口只不过是将隐式参数作为了compare方法中的显示参数,也就是原本的this变成了参数中的 T o1,如果不知道什么是隐式和显式参数我现在介绍一下,对于一个方法的调用,如a.sort(b),那么a就是这个方法的隐式参数,b是这个方法的显式参数,真正使用这个方法的时候,this就代表的是调用者a。
如上使用compareTo的方法中this.compareTo(user,sex)类似,compare方法只不过是直接将要比较的两个对象作为参数,compare(User user1,User user2),且调用者变为了比较器对象,例如Collections或Arrays等。
疑问解答

虽然User对象没有状态,不过还是需要建立这个对象的一个实例,我们需要这个实例来调用compare方法,因为这个compare方法并不是一个静态方法!!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/685281.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号