Java - 浅析 Comparable 和 Comparator

概述

Java 中我们知道基本数据类型,比如 intfloat 等可以使用 ==!=>< 来进行大小比较,但是对象或者包装类之间怎么进行比较呢,Java 也给我们提供了两个相关的类:ComparableComparator

public interface Comparable<T> {}
@FunctionalInterface
public interface Comparator<T> {}

那么它们两个有什么区别呢:

  • 从命名上

    从命名上,Comparable 是形容词,Comparator 是名词。可以理解为实现了 Comparable 接口的类具备了相互之间比较的能力;而 Comparator 的接口其中定义了一些默认的比较规则,还可以实现这个接口来自定义比较规则

  • 从源码上

    从源码上,Comparable 是一个接口,实现这个接口的类要重写其中定义的 compareTo() 方法;Comparator 是一个函数式接口,可以通过 lambda 表达式来使用

PriorityQueue

PriorityQueue 是一个优先级队列,其中的元素会按照它们的自然顺序排序(实现 Comparable 接口),或者由队列构造时提供的 Comparator 排序,两者必须存在一个。我们来看一下 PriorityQueue 的源码:

ublic class PriorityQueue<E> extends AbstractQueue<E>
    implements java.io.Serializable {

	// 自定义 Comparator,由构造方法传入
	private final Comparator<? super E> comparator;

	public PriorityQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }

	public PriorityQueue(Comparator<? super E> comparator) {
        this(DEFAULT_INITIAL_CAPACITY, comparator);
    }
	
	public PriorityQueue(int initialCapacity,
                         Comparator<? super E> comparator) {
        // Note: This restriction of at least one is not actually needed,
        // but continues for 1.5 compatibility
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.queue = new Object[initialCapacity];
        this.comparator = comparator;
    }

	public boolean add(E e) {
        return offer(e);
    }

	public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        modCount++;
        int i = size;
        if (i >= queue.length)
            grow(i + 1);
        size = i + 1;
        if (i == 0)
            queue[0] = e;
        else
        	// 添加的时候排序
            siftUp(i, e);
        return true;
    }

	private void siftUp(int k, E x) {
        if (comparator != null)
        	// 构造方法传入的 Comparator
            siftUpUsingComparator(k, x);
        else
        	// 使用类自身的 Comparable 能力
            siftUpComparable(k, x);
    }

	private void siftUpComparable(int k, E x) {
		// 如果类没有实现 Comparable 接口,这里会抛出 ClassCastException 类型转化异常
        Comparable<? super E> key = (Comparable<? super E>) x;
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (key.compareTo((E) e) >= 0)
            	// 如果要添加进来的值,大于等于 e,则不做任何操作
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = key;
    }

	private void siftUpUsingComparator(int k, E x) {
        while (k > 0) {
            int parent = (k - 1) >>> 1;
            Object e = queue[parent];
            if (comparator.compare(x, (E) e) >= 0)
            	// 如果
                break;
            queue[k] = e;
            k = parent;
        }
        queue[k] = x;
    }
}

接下来就通过 PriorityQueue 来理解 ComparableComparator 这两个概念。

Comparable

要理解 Comparable,我们首先来看一下 JavaInteger 类的源码:

public final class Integer extends Number implements Comparable<Integer> {
	...
	
	public int compareTo(Integer anotherInteger) {
        return compare(this.value, anotherInteger.value);
    }

	public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
    
	...
}

可以看到 Integer 类实现了 Comparable 接口,并且重写了 compareTo() 方法,说明 Integer 类具有了比较的能力。compareTo() 方法返回值是一个 int 类型的数字,为 -1 表示传入的对象大,为 0 表示一样大,1 表示 this 对象大。

使用 PriorityQueue 测试 IntegerComparable 的测试用例:

void testComparable() {
	// Integer 实现了 Comparable,所以这里可以使用无参构造器
   	Queue<Integer> queue = new PriorityQueue<>();
    queue.add(76);
    queue.add(1);
    queue.add(8);
    queue.add(4);
    queue.add(88);
    queue.add(54);

    System.out.println(queue.element());	// 1
}

Comparator

首先定义一个 People 类,只有一个年龄 age 属性:

@Data
@AllArgsConstructor
public class People {

    private Integer age;
}

定义一个 Comparator

public class MyComparator implements Comparator<People> {
    @Override
    public int compare(People o1, People o2) {
    	// 返回正整数表示 o1 > o2
        return o1.getAge() - o2.getAge();
    }
}

测试用例:

void testComparator() {
	// 这里一定要传入自定义的 Comparator
	Queue<People> queue = new PriorityQueue<>(new MyComparator());
    queue.add(new People(21));
    queue.add(new People(10));
    queue.add(new People(44));
    queue.add(new People(56));
    queue.add(new People(35));	// People(age=10)

    System.out.println(queue.element());
}

总结

对于 ComparableComparator 的应用还是非常简单的,从上面两个示例中基本就能理解,所以就不做过多的解释了,无非是要分清楚谁大谁小而已:

  • 对于实现 Comparable 接口的 compareTo() 方法来说,返回值为正表示传入的对象大,为负表示传入的对象小于 this 对象。

  • 对于实现 Comparator 接口的 compare() 方法来说,返回值为正表示传入的第一个对象大于第二个对象,为负表示第一个对象小于第二个对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中,ComparableComparator都是用于进行对象比较的接口。它们的用法如下: 1. Comparable接口 Comparable接口是Java内置的接口,它包含一个方法compareTo(),用于比较对象的大小。实现该接口的类可以直接进行排序。 例如,我们定义一个Person类实现Comparable接口: ``` public class Person implements Comparable<Person> { private String name; private int age; public Person(String name, int age) { this.name = name; this.age = age; } public int compareTo(Person person) { // 按照年龄进行排序 return this.age - person.age; } } ``` 在这个例子中,我们通过实现Comparable接口,并重写compareTo()方法,按照年龄进行排序。 使用Comparable接口进行排序的例子: ``` List<Person> list = new ArrayList<Person>(); list.add(new Person("Tom", 20)); list.add(new Person("Jerry", 18)); list.add(new Person("Jack", 25)); Collections.sort(list); for(Person p : list) { System.out.println(p.getName() + " " + p.getAge()); } ``` 输出结果: ``` Jerry 18 Tom 20 Jack 25 ``` 2. Comparator接口 Comparator接口也是Java内置的接口,它包含一个方法compare(),用于比较两个对象的大小。实现该接口的类可以定制不同的比较规则。 例如,我们定义一个PersonComparator类实现Comparator接口: ``` public class PersonComparator implements Comparator<Person> { public int compare(Person p1, Person p2) { // 按照姓名进行排序 return p1.getName().compareTo(p2.getName()); } } ``` 在这个例子中,我们通过实现Comparator接口,并重写compare()方法,按照姓名进行排序。 使用Comparator接口进行排序的例子: ``` List<Person> list = new ArrayList<Person>(); list.add(new Person("Tom", 20)); list.add(new Person("Jerry", 18)); list.add(new Person("Jack", 25)); Collections.sort(list, new PersonComparator()); for(Person p : list) { System.out.println(p.getName() + " " + p.getAge()); } ``` 输出结果: ``` Jack 25 Jerry 18 Tom 20 ``` 总之,ComparableComparator都是用于对象比较的接口。使用Comparable接口可以方便地对实现该接口的对象进行排序,而使用Comparator接口可以定制不同的比较规则。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值