应该比较另一种类型吗? [英] Should Comparable ever compare to another type?

查看:94
本文介绍了应该比较另一种类型吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想知道以下是否有一个有效的用例:

I'm wondering if there's ever a valid use case for the following:

class Base {}

class A implements Comparable<Base> {
    //...
}

这似乎很常见模式(有关示例,请参阅集合) )接受 T 类型的集合,其中 T扩展Comparable<?超级T>

It seems to be a common pattern (see Collections for a number of examples) to accept a collection of type T, where T extends Comparable<? super T>.

但是在技术上似乎无法履行 compareTo() 比较时到基类,因为没有办法确保另一个类不会通过矛盾的比较来扩展基类。请考虑以下示例:

But it seems technically impossible to fulfill the contract of compareTo() when comparing to a base class, because there's no way to ensure that another class doesn't extend the base with a contradictory comparison. Consider the following example:

class Base {
    final int foo;
    Base(int foo) {
        this.foo = foo;
    }
}

class A extends Base implements Comparable<Base> {
    A(int foo) {
        super(foo);
    }
    public int compareTo(Base that) {
        return Integer.compare(this.foo, that.foo); // sort by foo ascending
    }
}

class B extends Base implements Comparable<Base> {
    B(int foo) {
        super(foo);
    }
    public int compareTo(Base that) {
        return -Integer.compare(this.foo, that.foo); // sort by foo descending
    }
}

我们有两个类扩展 Base 使用不遵循通用规则的比较(如果有共同规则,几乎肯定会在 Base )。然而,以下破坏的排序将编译:

We have two classes extending Base using comparisons that don't follow a common rule (if there were a common rule, it would almost certainly be implemented in Base). Yet the following broken sort will compile:

Collections.sort(Arrays.asList(new A(0), new B(1)));

仅接受 T扩展Comparable< T>会不会更安全?或者是否有一些用例来验证通配符?

Wouldn't it be safer to only accept T extends Comparable<T>? Or is there some use case that would validate the wildcard?

推荐答案

这是一个非常好的问题。首先,让我们从集合的原因开始,使用

This is a very good question. First, let's start with the reason why Collections use methods like

binarySearch(List<? extends Comparable<? super T>> list, T key)

的确,为什么不只是

binarySearch(List<? extends Comparable<T>> list, T key)

原因是 PECS 原则:制作人扩展,消费者超级。 binarySearch 做什么?它从列表中读取元素,然后通过值传递给 compareTo 函数来比较它们。由于它读取元素,因此列表充当生产者,因此第一部分 - 生产者扩展。这一点很明显,那么消费者超级部分怎么样?

The reason for this is the PECS principle: Producer Extends, Consumer Super. What does binarySearch do? It reads elements from the list and then compares them by passing their values to the compareTo function. Since it reads elements, the list acts as a producer, and hence the first part—Producer Extends. This one is obvious, so what about the Consumer Super part?

消费者超级基本上意味着如果你只是要将值传递给某些功能,你就不会真正关心它是否接受你的对象的确切类型或它的一些超类。那么 binarySearch 声明所说的是:只要能将任何内容传递给 compareTo 列表元素的方法。

Consumer Super basically means that if you're only going to pass values to some function, you don't really care whether it accepts the exact type of your object or some superclass of it. So what the binarySearch declaration is saying is: I can look for anything as long as that anything can be passed to the compareTo method of the list elements.

在排序的情况下,它并不那么明显,因为元素只是相互比较。但即便如此,如果 Base 实际上实现 Comparable< Base> (并进行整个比较)和 A B 只是扩展 Base 而不用任何方式触及比较?然后你将无法对 A B 的列表进行排序,因为它们没有实现分别是可比较的< A> 可比较< B> 。每次子类化时都必须重新实现整个接口!

In the case of sorting it's not that obvious, because the elements are only compared to each other. But even then, what if Base actually implements Comparable<Base> (and does the whole comparison) and A and B just extend Base without touching comparison in any way? Then you would be unable to sort lists of A and B because they don't implement Comparable<A> and Comparable<B> respectively. You'd have to reimplement the whole interface each time you subclass!

另一个例子:如果有人想在包含某些类的实例的列表上进行二进制搜索,该怎么办?甚至不扩展你的 Base

Another example: what if someone wanted to do a binary search on a list containing instances of some class that doesn't even extend your Base?

class BaseComparable implements Comparable<Base> {
    private final Base key;
    // other fields

    BaseComparable(Base key, ...) {
        this.key = key;
        // other fields initialization
    }

    @Override
    public int compareTo(Base otherKey) {
        return this.key.compareTo(otherKey);
    }
};

现在他们想要使用 A 作为此二进制搜索的关键。他们只能因为而这样做?超级T 部分。请注意,此类不知道密钥是 A 还是 B ,因此无法实现可比较< A / B>

And now they want to use an instance of A as the key for this binary search. They can only do it because of the ? super T part. Note that this class has no idea about whether the key is an A or a B so it can't possibly implement Comparable<A/B>.

至于你的例子,我想这只是设计不佳的一个例子。不幸的是,在没有违反PECS原则和/或限制已经有限的Java泛型功能的情况下,我认为无法阻止此类事情。

As for your example, I guess it is just an example of poor design. Unfortunately, I see no way of preventing such things without breaking the PECS principle and/or limiting already limited functionality of Java generics.

这篇关于应该比较另一种类型吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆