Java中的比较器详细解析

 更新时间:2023年11月29日 10:07:25   作者:时代&信念  
这篇文章主要介绍了Java中的比较器详细解析,基本数据类型的数据(除boolean类型外)需要比较大小的话,直接使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的,需要的朋友可以参考下

引入的背景

我们知道基本数据类型的数据(除boolean类型外)需要比较大小的话,直接使用比较运算符即可,但是引用数据类型是不能直接使用比较运算符来比较大小的。那么,如何解决这个问题呢?

在Java中经常会涉及到对象数组的排序问题,那么就涉及到对象之间的比较问题。 Java实现对象排序的方式有两种:

  • 自然排序:java.lang.Comparable
  • 定制排序:java.util.Comparator

自然排序:java.lang.Comparable

Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序。

实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即通过 compareTo(Object obj) 方法的返回值来比较大小。

  • 如果当前对象this大于形参对象obj,则返回正整数。
  • 如果当前对象this小于形参对象obj,则返回负整数。
  • 如果当前对象this等于形参对象obj,则返回零。
package java.lang;

public interface Comparable{
    int compareTo(Object obj);
}

Comparable 的典型实现:(默认都是从小到大排列的)

  • String:按照字符串中字符的Unicode值进行比较
  • Character:按照字符的Unicode值来进行比较
  • 数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值大小进行比较
  • Boolean:true 对应的包装类实例大于 false 对应的包装类实例
  • Date、Time等:后面的日期时间比前面的日期时间大

测试String

代码示例:

 @Test
    public void test1(){
        //测试String已经写好的
        String [] a = new String[]{"Jack", "Tom", "Lucy"};

        //排序之前
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+"\t");
        }

        System.out.println();
        //使用Arrays进行排序
        Arrays.sort(a);

        //排序之后进行展示
        for (int i = 0; i < a.length; i++) {
            System.out.print(a[i]+"\t");
        }
    }

运行效果:

在这里插入图片描述

测试自己实现comparable接口

Product类

package cn.edu.chd.exer1;

import java.util.Objects;


public class Product implements Comparable{
    private String name;
    private double prices;

    //无参构造
    public Product() {
    }

    //全参构造
    public Product(String name, double prices) {
        this.name = name;
        this.prices = prices;
    }

    public String getName() {
        return name;
    }

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

    public double getPrices() {
        return prices;
    }

    public void setPrices(double prices) {
        this.prices = prices;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Product product = (Product) o;
        return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, prices);
    }

    @Override
    public int compareTo(Object o) {
        //如果是同一个对象,return 0
        if (this == o){
            return 0;
        }

        //两个对象比较的标准是:价格从小到大,价格一样的话,按照名字从小到大
        if (o instanceof Product){
            Product p = (Product)o;
            int v = Double.compare(this.prices, p.prices);
//            return v;
            if (v != 0){
                return v;
            }
            //价格如果相同,名字按照从小到大
            return this.name.compareTo(p.name);
        }
        //手动抛异常
        throw new RuntimeException("类型不匹配");

    }
}

测试

    //对不同对象的大小进行排序
    @Test
    public void test2(){

        //商品数组
        Product[] products = new Product[5];
        //全参构造器,在new对象时就对属性进行赋值
        products[0] = new Product("Huawei", 5999);
        products[1] = new Product("XiaoMi", 4999);
        products[2] = new Product("iPhone", 9999);
        products[3] = new Product("vivo", 3999);
        products[4] = new Product("Honer", 5999);


        System.out.println("排序之前");
        //排序之前的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }

        System.out.println("----------------------------------------------");
        //使用arrays进行排序
        Arrays.sort(products);

        System.out.println("排序之后");
        //排序后的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }
        
    }

运行效果

在这里插入图片描述

定制排序:java.util.Comparator

思考

  • 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码(例如:一些第三方的类,你只有.class文件,没有源文件)
  • 如果一个类,实现了Comparable接口,也指定了两个对象的比较大小的规则,但是此时此刻我不想按照它预定义的方法比较大小,但是我又不能随意修改,因为会影响其他地方的使用,怎么办?(例如:我想要String按照字母从大到小的顺序排序,而不是默认的从小到大)

JDK在设计类库之初,也考虑到这种情况,所以又增加了一个java.util.Comparator接口。强行对多个对象进行整体排序的比较。

  • 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
  • 可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。

Product类

package cn.edu.chd.exer2;

import java.util.Objects;


public class Product implements Comparable{
    private String name;
    private double prices;

    //无参构造
    public Product() {
    }

    //全参构造
    public Product(String name, double prices) {
        this.name = name;
        this.prices = prices;
    }

    public String getName() {
        return name;
    }

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

    public double getPrices() {
        return prices;
    }

    public void setPrices(double prices) {
        this.prices = prices;
    }

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

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Product product = (Product) o;
        return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, prices);
    }

    @Override
    public int compareTo(Object o) {
        //如果是同一个对象,return 0
        if (this == o){
            return 0;
        }

        //两个对象比较的标准是:价格从小到大,价格一样的话,按照名字从小到大
        if (o instanceof Product){
            Product p = (Product)o;
            int v = Double.compare(this.prices, p.prices);
//            return v;
            if (v != 0){
                return v;
            }
            //价格如果相同,名字按照从小到大
            return this.name.compareTo(p.name);
        }
        //手动抛异常
        throw new RuntimeException("类型不匹配");

    }
}

按照商品的价格从低到高排序的comparator

 @Test
    public void test1(){
        //new一个comparator接口的匿名实现类
        Comparator comparator = new Comparator() {
            //按照商品的价格从低到高排序
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 == o2){
                    return 0;
                }
                if (o1 instanceof Product && o2 instanceof Product){
                    //强转
                    Product p1 = (Product) o1;
                    Product p2 = (Product) o2;
                    return Double.compare(p1.getPrices(), p2.getPrices());

                }
                throw new RuntimeException("类型不匹配");

            }
        };

        //商品数组
        Product[] products = new Product[5];
        //全参构造器,在new对象时就对属性进行赋值
        products[0] = new Product("Huawei", 5999);
        products[1] = new Product("XiaoMi", 4999);
        products[2] = new Product("iPhone", 9999);
        products[3] = new Product("vivo", 3999);
        products[4] = new Product("Honer", 5999);


        System.out.println("排序之前");
        //排序之前的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }

        System.out.println("----------------------------------------------");
        //将comparator对象作为参数进行传入,排序
        Arrays.sort(products, comparator);

        System.out.println("排序之后");
        //排序后的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }



        
    }

运行效果:

在这里插入图片描述

按照名称进行排序的comparator

   //按照名称进行排序
    @Test
    public void test2(){
        //new一个comparator接口的匿名实现类
        Comparator comparator = new Comparator() {
            //按照商品的名称进行排序
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 == o2){
                    return 0;
                }
                if (o1 instanceof Product && o2 instanceof Product){
                    //强转
                    Product p1 = (Product) o1;
                    Product p2 = (Product) o2;
                    return p1.getName().compareTo(p2.getName());

                }
                throw new RuntimeException("类型不匹配");

            }
        };

        //商品数组
        Product[] products = new Product[5];
        //全参构造器,在new对象时就对属性进行赋值
        products[0] = new Product("Huawei", 5999);
        products[1] = new Product("XiaoMi", 4999);
        products[2] = new Product("iPhone", 9999);
        products[3] = new Product("vivo", 3999);
        products[4] = new Product("Honer", 5999);


        System.out.println("排序之前");
        //排序之前的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }

        System.out.println("----------------------------------------------");
        //将comparator对象作为参数进行传入,排序
        Arrays.sort(products, comparator);

        System.out.println("排序之后");
        //排序后的遍历
        for (int i = 0; i < products.length; i++) {
            System.out.println(products[i]);
        }


    }

运行效果:

在这里插入图片描述

到此这篇关于Java中的比较器详细解析的文章就介绍到这了,更多相关Java中的比较器内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • StringBuilder为什么线程不安全深入讲解

    StringBuilder为什么线程不安全深入讲解

    这篇文章主要给大家介绍了关于StringBuilder为什么线程不安全的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用StringBuilder线程具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • java中常见的中文乱码总结

    java中常见的中文乱码总结

    本文主要介绍了java中常见的中文乱码以及解决方法,主要包括字节码文件读取时出现的乱码问题,本文通过实例代码给大家介绍的非常详细,具有很好的参考价值,感兴趣的朋友跟随小编一起看看吧
    2017-03-03
  • Springboot详解RocketMQ实现广播消息流程

    Springboot详解RocketMQ实现广播消息流程

    RocketMQ作为一款纯java、分布式、队列模型的开源消息中间件,支持事务消息、顺序消息、批量消息、定时消息、消息回溯等,本篇我们了解如何实现广播消息
    2022-06-06
  • IDEA 中使用 Big Data Tools 连接大数据组件

    IDEA 中使用 Big Data Tools 连接大数据组件

    本文主要介绍了IDEA 中使用 Big Data Tools 连接大数据组件,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 浅谈基于SpringBoot实现一个简单的权限控制注解

    浅谈基于SpringBoot实现一个简单的权限控制注解

    这篇文章主要介绍了基于SpringBoot实现一个简单的权限控制注解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • 浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别

    浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别

    下面小编就为大家带来一篇浅谈Java异常的Exception e中的egetMessage()和toString()方法的区别。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-07-07
  • Java中Druid连接池连接超时获取不到连接的解决

    Java中Druid连接池连接超时获取不到连接的解决

    这篇文章主要介绍了Java中Druid连接池连接超时获取不到连接的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • Java令牌Token登录与退出的实现

    Java令牌Token登录与退出的实现

    这篇文章主要介绍了Java令牌Token登录与退出的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-05-05
  • 浅试仿 mapstruct实现微服务编排框架详解

    浅试仿 mapstruct实现微服务编排框架详解

    这篇文章主要为大家介绍了浅试仿 mapstruct实现微服务编排框架详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-08-08
  • 一篇文章让你弄懂Java运算符

    一篇文章让你弄懂Java运算符

    java中位运算符主要有按位与&、按位或|、按位非~、按位异或^, 在使用时需要将运算数都转换为二进制再进行运算,若为负数则使用补码表示,这篇文章主要给大家介绍了关于Java运算符的相关资料,需要的朋友可以参考下
    2022-03-03

最新评论