当前位置: 首页 > 知识库问答 >
问题:

如何为可比较类和具有比较器的类编写有序集合

段干英杰
2023-03-14

我对在Java中实现一个特殊的优先级队列变体很感兴趣,我希望这个优先级队列能够与泛型类型一起工作。在Java的集合对象中,存储具有某种排序的对象(例如PriorityQueue、TreeSet等),可以使用实现Compariable的类以及不一定实现Compariable的类,因为类的比较器传递给构造函数。

如何在优先级队列类中实现此功能?如果给我一个比较器,我是否必须根据类是否实现Comparable vs重写所有方法?或者有没有一种方法可以从实现Comparable的类中获得一个比较器,所以我只需要处理比较器的情况?

共有2个答案

乔伯寅
2023-03-14

内置的PriorityQueue具有构造函数,用于使用可比较对象创建队列,以及使用比较器创建队列:

  • PriorityQueue()根据元素的自然顺序对其进行排序

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

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

如果要确保在不提供比较器的情况下在不可比较的对象上创建集合时出现编译错误,可以使用factory方法来防止:

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
公良琛
2023-03-14

首先,Java中的PriorityQueue已经具有采用比较器的构造函数。如果您尝试子类化PriorityQueue,那么没有必要确定是否应该使用比较器与依赖可比。提供调用匹配超类构造函数的构造函数

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

如果提供了比较器,请将其存储起来以备将来使用。如果未提供比较器,则(假设Java 8)使用比较器的实例。自然领主。

没有Java 8,实现比较器。使用适配器模式的naturalOrder。此适配器类的类型参数被限制为可比较,因此,如果添加的对象不可比较,并且未提供比较器,则可能会导致类异常。没关系;如果要允许传入比较器进行比较,则不能将优先级队列的类型参数约束为可比较,因为比较器不会以这种方式限制其类型参数。

“比较”方法只是将“比较”委托给“比较”方法。

class ComparableToComparator<T extends Comparable<? super T>> implements Comparator<T> {
    @Override
    public int compare(T a, T b) {
        return a.compareTo(b);
    }
}

(这几乎就是Comparator.naturalOrder所做的。)

无论是否传入了比较器,您都可以使用比较器。它要么是传入的对象,要么是试图将对象视为可比较对象的上述类的实例。

 类似资料:
  • 问题内容: 我们有一些代码根据其坐标之间的距离对地址列表进行排序。这是通过使用自定义比较器的collections.sort完成的。 但是,列表中有时不包含地址,这会导致NullPointerException。解决这个问题的最初想法是让比较器返回至少0个坐标为零的地址的距离。我担心这可能导致列表中“有效”元素的顺序损坏。 因此是否可以在比较器中为空数据返回“ 0”值,还是有一种更干净的方法来解决

  • 问题内容: 我已经看到了同时实现Comparable和Comparator的类。这是什么意思?为什么我要一个使用另一个? 问题答案: 下面的文字来自Comparator vs Comparable 可比 可比较的对象能够将自己与另一个对象进行比较。类本身必须实现java.lang.Comparable接口,以便能够比较其实例。 比较器 比较器对象能够比较两个不同的对象。该类不是在比较其实例,而是在

  • 当我在浏览上面的接口时,在阅读了许多相同主题的站点后,我对这些接口的语法不是很清楚。 请考虑以下代码段: 如果每个查询都是可理解的。

  • 对于某个项目,我必须按地区和名称订购一些数字。首先,它们按面积从大到小排序,如果它们一致,则按字母顺序排序。在一个名为的类中,我有一个类型如下的内部类: 如果我想从另一个类对一组进行排序,我该如何做?我认为最好的方法是下面的,但失败了(

  • 问题内容: 我正在创建一个简单的程序来了解Java Comparator类。我已经按顺序进行了排序,但是现在我想按降序对列表进行排序,但是由于使用了实现的内部类(歌曲是容纳getter和setter方法的歌曲类),在调用该方法时遇到了问题。 这是我的课程,里面包含分类过程等。 这是我的简单课程; 有人可以帮我弄清楚我将在类中调用该方法的地方,因为它无法编译? 问题答案: 编辑2015年7月 由于此

  • 问题内容: 我需要编写一个比较器,它采用类型A的对象A和类型B的对象B。这两个对象不是公共对象的扩展。它们的确不同,但是我需要通过其中的通用字段来比较这两个对象。我必须使用比较器接口,因为对象存储在Set中,并且在必须对CollectionUtils执行操作之后。我在Google上搜索了一下,发现了Comparator的解决方案,但只有相同的类型。 我试图朝这个方向实施思考,但是我不知道我是否在正