如何用Comparators编写一个有序的集合和类的有序集合

时间:2018-02-27 18:19:30

标签: java comparator comparable

我有兴趣在Java中实现Priority Queue的特殊变体,我希望这个优先级队列能够使用泛型类型。在Java的集合对象中存储具有某种排序的对象(例如,PriorityQueue,TreeSet等),可以使用实现Comparable的类以及不必实现Comparable的类,给定将类的Comparator传递给构造函数。

如何在Priority Queue类中实现此功能?我是否必须重写我的所有方法,具体取决于该类是否实现Comparable vs如果我被赋予Comparator?或者有没有办法从实现Comparable的类中获取Comparator,所以我只需要处理Comparator案例?

2 个答案:

答案 0 :(得分:0)

首先,Java中的PriorityQueueconstructors take a Comparator。如果您尝试继承PriorityQueue,则无需确定是否应使用Comparator而不是Comparable。提供调用匹配超类构造函数的构造函数。

但是,如果您要创建自己的优先级队列,那么您可以在构建优先级队列时做出一次决定。

如果提供了Comparator,则将其存储以供日后使用。如果未提供Comparator,则(假设Java 8+)使用Comparator.naturalOrder的实例。

如果没有Java 8,请使用Adapter pattern实施Comparator.naturalOrder。此适配器类T的类型参数被限制为Comparable,因此如果添加的对象不是ClassCastExceptionComparable,则可能会产生Comparator没有供应。没关系;如果要允许传递Comparable进行比较,则不能将优先级队列的类型参数约束为Comparator,因为Comparator不会以这种方式限制其类型参数

compare方法只需委托Comparable的{​​{1}}方法。

compareTo

(这几乎是class ComparableToComparator<T extends Comparable<? super T>> implements Comparator<T> { @Override public int compare(T a, T b) { return a.compareTo(b); } } 所做的。)

是否传入Comparator.naturalOrder,您需要使用Comparator。它是传入的那个,或上述类的一个实例,它试图将对象视为Comparator

答案 1 :(得分:0)

内置PriorityQueue具有使用Comparable对象创建队列的构造函数,以及使用Comparator创建队列的构造函数:

使用类似语义实现自己的类的最简单方法是始终使用Comparator,并且在没有提供时使用自然比较器:

public class MyOrderedCollection<E> {

    private final Comparator<? super E> comparator;

    @SuppressWarnings("unchecked")
    public MyOrderedCollection() {
        this((Comparator<? super E>) Comparator.naturalOrder());
    }

    public MyOrderedCollection(Comparator<? super E> comparator) {
        this.comparator = comparator;
    }
}

如果要确保在不提供Comparable的情况下在非Comparator的对象上创建集合时出现编译错误,则可以使用工厂方法来防范:

public class MyOrderedCollection<E> {

    private final Comparator<? super E> comparator;

    public static <E extends Comparable<? super E>> MyOrderedCollection<E> of() {
        return new MyOrderedCollection<>(Comparator.naturalOrder());
    }

    public static <E> MyOrderedCollection<E> of(Comparator<? super E> comparator) {
        return new MyOrderedCollection<>(comparator);
    }

    private MyOrderedCollection(Comparator<? super E> comparator) {
        this.comparator = comparator;
    }
}

现在你甚至不必压制编译警告。

有了它,就像这样:

MyOrderedCollection<String> x = MyOrderedCollection.of();

MyOrderedCollection<Object> y = MyOrderedCollection.of(Comparator.comparing(Object::toString));

MyOrderedCollection<Object> z = MyOrderedCollection.of(); // compilation error