Bootstrap

Java——比较器

引入的背景

我们知道基本数据类型的数据(除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]);
        }


    }

运行效果:

在这里插入图片描述

;