【JAVA源码学习】Comparable接口

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

文章目录

  • 1. 接口概述
    • 1.1 用处
    • 1.2 注意点
  • 2. compare方法
  • 3. 使用方法
    • 3.1 实现了 Comparable接口的类
    • 3.2 自定义类

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());
        }
    }

运行,结果:
【JAVA源码学习】Comparable接口_第1张图片
接下来,我们实现 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;
        }
    }

	// 省略其他函数
}

再次执行结果:
【JAVA源码学习】Comparable接口_第2张图片
而且,此使执行:new User(5).compareTo(null);
【JAVA源码学习】Comparable接口_第3张图片
满足 Comparable接口的要求

你可能感兴趣的:(JAVA源码学习)