[Java] Comparable接口/compareTo方法的介绍和使用

背景

Java作为一门面向对象的编程语言,里面的一切几乎都是由类和对象组成的。而正常情况下,对象之间只能进行比较操作( == 或 != ),而不能使用诸如>,<等判断大小的符号。
但是在实际的开发应用中,对对象排序的需求又确实存在,而排序则必须要确立一种比较大小的方式,因此Comparable接口便应运而生。

介绍

首先我们先弄清楚一件事:Comparable是一个接口,当一个类的对象间有排序或比较的需求时,就可以令这个类实现这个接口。注意,这个接口是带泛型的,泛型指定的是需要比较的类。

public class Product implements Comparable<Product> {...

该接口里只有一个方法:compareTo(T o),T表示泛型,只需要重写了这个方法,即可实现对象之间的比较与排序。

		@Override
    	public int compareTo(Product o) {...

需要注意的是,如String、包装类等已经实现了Comparable接口并重写了compareTo方法,默认进行的是从小到大的排列。

JDK1.8中String类重写的toString方法:

    public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;

        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
    }

对String的排序进行简单的演示:

	@Test
    public void test1(){
        String[] arr = new String[]{"AA","BB","ZZ","DD","CC"};
        Arrays.sort(arr);   // 对arr数组进行排序
        System.out.println(Arrays.toString(arr));	// [AA, BB, CC, DD, ZZ]
    }

重写规则

既然需要我们对compareTo方法进行重写,那么我们也需要知道其中一些规则。

  • 如果当前对象(调用这个方法的对象)大于形参对象(被比较的另一个对象),则返回正整数
  • 相等则返回0
  • 小于返回负整数

因此,了解了这些基础的规则后,我们便可以通过控制compareTo方法返回值的方式,人为地定义两个对象的大小。

使用举例

如上文所示,为了演示我们不妨定义一个Product类,同时使其实现Comparable接口:

public class Product implements Comparable {
    private String name;
    private double price;
    
    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }
    ...

这个类中有两个属性:名称name与价格price。参考现实的情况,当我们在电商平台购物时,往往会让商品以价格升序或降序的方式进行排序供我们挑选。因此,假定我们有了个需求:对Product的实例化对象按照他们的价格进行排序。

为了实现这个目的,我们需要恰当地重写compareTo方法:

    @Override
    public int compareTo(Product o) {
        if (this.price > product.price)
        	return 1;
        else if (this.price < product.price)
        	return -1;
        else 
        	return 0;
    }	// 这种写法是按价格从低到高进行排序

当然,这段代码可以写得再精简一点,不过这就是题外话了。

         return Double.compare(this.price,o.price);

测试一下:

	@Test
    public void test2(){
        Product[] arr = new Product[4];
        arr[0] = new Product("A",59);
        arr[1] = new Product("B",12);
        arr[2] = new Product("C",44);
        arr[3] = new Product("D",102);

        Arrays.sort(arr);   // 排序,未实现Comparable接口时会抛异常

        System.out.println(Arrays.toString(arr));
        // [Goods{name='B', price=12.0}, Goods{name='C', price=44.0}, Goods{name='A', price=59.0}, Goods{name='D', price=102.0}]
    }

可以看到排序后的数组中Product对象的确是以价格升序进行排列的。

若我们需要按价格降序排序?很简单,在原有代码的基础上return的整数前添个负号即可:

         return -Double.compare(this.price,o.price);

多级排序

上述代码已经初步达成了我们的需求,而更进一步地想,当两个Prodect对象的价格相同时,是否可以实现按其名称关系再进行排序?这就引出我们的下一步操作:多级排序。

同样的案例,以二级排序为例,其实很简单,在源代码基础上稍作修改即可。代码如下:

 	@Override
    public int compareTo(Product o) {
        if (this.price > product.price)
        	return 1;
        else if (this.price < product.price)
        	return -1;
        else 
        	return this.name.compareTo(o.name);
    }

只需要修改else下的情况,令两个对象的name再比较一次即可。

这里String类的name是自身已实现了Comparable接口的类,所以可以直接调用其的compareTo方法。若比较的是其他自定义类,则需要该类也实现了Comparable接口或者直接在当前代码块下手动补充大小的比较标准。

同样道理,利用这种多层嵌套的方式可以实现更高层次的多级排序。

推荐搭配食用:Comparator/compare,一次学俩。

你可能感兴趣的:([Java] Comparable接口/compareTo方法的介绍和使用)