源码学习 Java.lang.Comparable<T>

本文介绍了Java中的Comparable接口,包括接口概述、compare方法的实现细节以及如何在自定义类中使用Comparable接口进行排序。Comparable接口用于实现对象的自然排序,其compareTo方法是自然比较方法。文章通过Integer类和自定义类的例子,展示了Comparable接口在排序和存储中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在学习 String类源码的时候,发现了 Comparable接口,觉得有必要先学习一下这个接口的用法。

1. 接口概述

Comparable接口对实现它的每个类的对象强加一个总排序,这种排序被称为类的自然排序,类的compareTo方法被称为自然比较方法。

1.1 用处

实现此接口的对象的列表(和数组)可以通过Collections.sort(),以及Arrays.sort()自动排序。实现此接口的对象可以用作SortedMap有序映射中的键,也可以用作SortedSet有序集中的元素,而无需指定比较器。

1.2 注意点

① null不是任何类的实例,并且e.compareTo(null)应抛出NullPointerException;
② 当且仅当e1.compareTo(e2)== 0具有与C类的每个e1和e2的e1.equals(e2)相同的布尔值时,C类的自然排序被认为与equals一致。这里注意,并不是规定自然排序与equals要一致,而是强烈建议(尽管不要求)自然排序与equals一致。几乎所有实现Comparable接口的Java核心类都具有与equals一致的自然排序。一个例外是java.math.BigDecimal,其自然顺序等同于具有相同值和不同精度的BigDecimal对象(例如4.0和4.00)

2. compare方法

打开 Comparable接口的源码,发现只有一个方法:

public interface Comparable<T> {
	/**
	 * @param   o 用于比较的对象
     * @return  负整数,零或正整数,对应此对象小于,等于或大于传入的比较对象
     * @throws NullPointerException 传入的 o为 null
     * @throws ClassCastException 传入的 o的对象类型阻止与此对象进行比较
     */
    public int compareTo(T o);
}

要实现 Comparable接口,则要实现该方法,而实现方法时应注意:
① 实现者必须确保所有x和y的sgn(x.compareTo(y)) == -sgn(y.compareTo(x))。这意味着如果y.compareTo(x)抛出异常,x.compareTo(y)必须抛出异常。(符号sgn表达式表示数学signum函数,定义为返回 -1,0,1 其中一个,根据表达式的值为负,零或正)
② 实现者还必须确保关系是可传递的。x.compareTo(y) == 0 && y.compareTo(z) == 0 可以推导:x.compareTo(z) == 0
③ 实现者必须确保x.compareTo(y) == 0 意味着sgn(x.compareTo(z)) == sgn(y.compareTo(z)),对于所有z都成立
④ 最后,强烈建议,但不严格要求(x.compareTo(y) == 0) == (x.equals(y))

关于最后这一点强烈建议,在 jdk1.8中给出的原因是:

  • 例如,如果添加两个键 a和 b ,!a.equals(b) && (a.compareTo(b) == 0)对于不使用显式比较器的有序集,第二个 add操作返回false(并且有序集的大小不会增加),因为 a和 b在有序集的透视图中是等效的
  • 相当于,两个元素判断为不同,则可以同时加入到有序集中,但他们的自然排序又是相同的,找不到插入的位置,有些许矛盾

3. 使用方法

3.1 实现了 Comparable接口的类

对于已经实现了 Comparable接口的类,正如我们上面提到的:

  • 实现此接口的对象的列表(和数组)可以通过Collections.sort(),以及Arrays.sort()自动排序
  • 实现此接口的对象可以用作SortedMap有序映射中的键,也可以用作SortedSet有序集中的元素,而无需指定比较器

例如,对于 Integer类,其源码中已经实现了 Comparable接口:

public final class Integer extends Number implements Comparable<Integer> {}

因此:

	public static void main(String[] args) {
        Integer[] a = new Integer[]{1, 15, 6, 18, 50, 3};
        Arrays.sort(a);
        for (Integer k : a
             ) {
            System.out.print(k + " ");
        }
    }

打印结果:
在这里插入图片描述

3.2 自定义类

例如对于下面的类:

public class User {
   
    private String name;
    private String phoneNumber;
    private Integer old;
    
    User(){}

    User(Integer old) {
        this.old = old;
    }
	// get、set方法
}

我们要实现跟上面的 Integer一样,用Arrays.sort()排序,该如何做呢?
我们先直接进行测试:

    public static void main(String[] args) {
        User[] users = new User[5];
        users[0] = new User(50);
        users[1] = new User(5);
        users[2] = new User(4);
        users[3] = new User(30);
        users[4] = new User(1);
        Arrays.sort(users);
        for (User user : users
             ) {
            System.out.println(user.toString());
        }
    }

运行,结果:
在这里插入图片描述
接下来,我们实现 Comparable接口:

public class User implements Comparable<User> {

    @Override
    public int compareTo(User o) {
        if (this.old > o.old) {
            return 1;
        } else if (this.old < o.old) {
            return -1;
        } else {
            return 0;
        }
    }

	// 省略其他函数
}

再次执行结果:
在这里插入图片描述
而且,此使执行:new User(5).compareTo(null);
在这里插入图片描述
满足 Comparable接口的要求

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值