比较器(Comparable和Comparator)、自然排序、定制排序

写在前面: 我是「扬帆向海」,这个昵称来源于我的名字以及女朋友的名字。我热爱技术、热爱开源、热爱编程。技术是开源的、知识是共享的。

这博客是对自己学习的一点点总结及记录,如果您对 Java算法 感兴趣,可以关注我的动态,我们一起学习。

用知识改变命运,让我们的家人过上更好的生活

比如Integer,double等基本类型数据,Java可以对他们进行比较排序,但是在 Java 中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题 。

一、java中的sort()方法

在java.util.Collections类中有个sort()方法,主要是用来给数组排序

public class CompareTest1 {
    @Test
    public void test() {
        String[] arr = new String[]{"AA", "SS", "FF", "OO", "EE", "HH"};
        System.out.println("排序之前: " + Arrays.toString(arr));
        Arrays.sort(arr);
        System.out.println("排序之后: " + Arrays.toString(arr));
    }
}

代码执行结果:

排序之前: [AA, SS, FF, OO, EE, HH]
排序之后: [AA, EE, FF, HH, OO, SS]

需求:商场有一批水果,对水果的价格进行排序

水果类:

public class Fruit {
    private String name;
    private double price;

    public Fruit() {
    }

    public Fruit(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

测试类:

public class CompareTest2 {
    @Test
    public void test() {
        Fruit[] arr = new Fruit[5];
        arr[0] = new Fruit("apple", 18);
        arr[1] = new Fruit("pear", 6);
        arr[2] = new Fruit("banana", 14);
        arr[3] = new Fruit("watermelon", 26);
        arr[4] = new Fruit("tomato", 6);
        System.out.println("排序之前: " + Arrays.toString(arr));
        // 排序
        Arrays.sort(arr);
        System.out.println("排序之后: " + Arrays.toString(arr));
    }
}

程序将会报错:

java.lang.ClassCastException: xxx.Fruit cannot be cast to java.lang.Comparable

报错原因:类型转换错误

为了解决这个错误,对象之间的排序将用到比较器。

Java 实现对象排序的方式有两种:

自然排序: java.lang.Comparable

定制排序: java.util.Comparator

二、自然排序:Comparable

1.自然排序的定义

Comparable 接口强行对实现它的每个类的对象进行整体排序

2.实现过程

实现 Comparable接口的类必须实现 compareTo(Object obj) 方法,两个对象通过 compareTo方法的返回值来比较大小 。
① 如果当前对象 this 大于形参对象 obj 则返回正整数;
② 如果当前对象 this 小于 形参对象 obj则返回 负整数;
③ 如果当前对象 this 等于 形参对象 obj 则返回零 。
实现 Comparable接口的对象列表(和数组)可以通过 Collections.sort 或 Arrays.sort 进行自动排序。
实现此接口的对象可以用作有序映射中的键或有序集合中的集合,无需指定比较器

为了解决类型转换错误,在水果类里面实现Comparable接口。

3.示例代码

水果类:

public class Fruit implements Comparable<Fruit> {
    private String name;
    private double price;

    public Fruit() {
    }

    public Fruit(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Fruit{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    // 水果价格从低到高进行排序,若价格相同则按水果名称从高到低排序
    @Override
    public int compareTo(Fruit fruit) {
        if (this.price > fruit.price) {
            return 1;
        } else if (this.price < fruit.price) {
            return -1;
        } else {
            // this.name.compareTo(fruit.name) 按名称从低到高,前面加负号,表示相反
            return -this.name.compareTo(fruit.name);
        }
    }
}

注:测试类代码同Test2
代码执行结果:

排序之前: [Fruit{name='apple', price=18.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='tomato', price=6.0}]
排序之后: [Fruit{name='tomato', price=6.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='apple', price=18.0}, Fruit{name='watermelon', price=26.0}]

三、定制排序 :Comparator

在实际开发中,遇到当元素的类型实现了Comparable 接口,但是它的排序方式不适合当前的操作;或者根本没有实现Comparable
接口,而又不方便修改代码。那么可以考虑使用 Comparator 的对象进行排序。

1.实现过程

定义一个比较器对象;
重写 compare(Object o1,Object o2) 方法,比较 o1 和 o2 的大小:
① 如果方法返回正整数,则表示 o1 大于 o2 ;
② 如果方法返回 0 ,表示相等;
③ 如果方法返回负整数,表示o1 小于 o2 。

可以 将 Comparator 传递给 sort 方法,从而允许在排序顺序上实现精确控制 。

2.示例代码
public class CompareTest3 {
    /**
     * 按字符从大到小进行排序
     */
    @Test
    public void test() {
        String[] arr = new String[]{"AA", "CC", "KK", "MM", "GG", "FF", "DD"};
        System.out.println("原来的字符串: " + Arrays.toString(arr));
        Arrays.sort(arr, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return -o1.compareTo(o2);
            }
        });
        System.out.println("按字符从大到小排序后的字符串: " + Arrays.toString(arr));
    }
}

代码执行结果:

原来的字符串: [AA, CC, KK, MM, GG, FF, DD]
按字符从大到小排序后的字符串: [MM, KK, GG, FF, DD, CC, AA]

对水果的价格进行排序

注:水果类同前,节省篇幅,在此不再重复。

public class CompareTest4 {
    @Test
    public void test() {
        Fruit[] arr = new Fruit[5];
        arr[0] = new Fruit("apple", 18);
        arr[1] = new Fruit("pear", 6);
        arr[2] = new Fruit("banana", 14);
        arr[3] = new Fruit("watermelon", 26);
        arr[4] = new Fruit("watermelon", 6);
        System.out.println("排序之前: " + Arrays.toString(arr));

        Arrays.sort(arr, new Comparator<Fruit>() {
            // 按照水果名称从低到高排序,若名称相同则按照价格从高到低排序
            @Override
            public int compare(Fruit o1, Fruit o2) {
                if (o1.getName().equals(o2.getName())) {
                    return -Double.compare(o1.getPrice(), o2.getPrice());
                } else {
                    return o1.getName().compareTo(o2.getName());
                }
            }
        });
        System.out.println("排序之后: " + Arrays.toString(arr));
    }
}

代码执行结果:

排序之前: [Fruit{name='apple', price=18.0}, Fruit{name='pear', price=6.0}, Fruit{name='banana', price=14.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='watermelon', price=6.0}]
排序之后: [Fruit{name='apple', price=18.0}, Fruit{name='banana', price=14.0}, Fruit{name='pear', price=6.0}, Fruit{name='watermelon', price=26.0}, Fruit{name='watermelon', price=6.0}]

当定制排序和自然排序同时存在时,最终的排序结果是按照定制排序进行排序的。

上一篇 聊聊 StringBuffer 与 StringBuilder

  • 31
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
自然排序比较排序是两种不同的排序方式。 自然排序是指使用对象的默认排序规则进行排序。在Java中,如果一个类实现了Comparable接口,并重写了compareTo方法,那么这个类的对象就可以通过Collections.sort()或Arrays.sort()等方法进行自然排序自然排序的好处是简单方便,只需要实现Comparable接口并定义好排序规则即可。 比较排序则是通过实现Comparator接口来进行排序Comparator接口中有一个compare方法,我们可以根据自己的需求,在该方法中定义排序规则。比较排序的好处是可以对同一对象进行多种不同方式的排序,同时将比较排序算法和具体的实体类分离,使得排序算法的变化不会影响到实体类的代码。 在使用比较排序时,我们可以通过传入不同的Comparator对象来实现不同的排序方式。比较排序的灵活性更高,适用于需要多种不同排序规则的情况。 总结来说,自然排序是使用对象的默认排序规则进行排序,而比较排序则是通过实现Comparator接口来定义排序规则。根据具体的需求,我们可以选择使用自然排序比较排序来对对象进行排序。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [Java中自然排序比较排序详解](https://blog.csdn.net/weixin_58463882/article/details/121493340)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值