我想知道以下是否有一个有效的用例:
class Base {} class A implements Comparable{ //... }
这似乎是一个常见的模式(见集合了大量的实例)接受类型的集合T
,其中T extends Comparable super T>
.
但是在技术上似乎不可能compareTo()
在与基类进行比较时履行合同,因为没有办法确保另一个类不会通过相互矛盾的比较扩展基础.请考虑以下示例:
class Base { final int foo; Base(int foo) { this.foo = foo; } } class A extends Base implements Comparable{ 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 { B(int foo) { super(foo); } public int compareTo(Base that) { return -Integer.compare(this.foo, that.foo); // sort by foo descending } }
我们有两个类Base
使用不遵循通用规则的比较进行扩展(如果存在共同规则,则几乎肯定会实现Base
).然而,以下破坏的排序将编译:
Collections.sort(Arrays.asList(new A(0), new B(1)));
只接受会不会更安全T extends Comparable
?或者是否有一些用例可以验证通配符?
这个问题问得好.首先,让我们从Collections
使用方法的原因开始
binarySearch(List extends Comparable super T>> list, T key)
的确,为什么不呢
binarySearch(List extends Comparable> list, T key)
其原因是PECS原则:Producer Extends,Consumer Super.怎么binarySearch
办?它从列表中读取元素,然后通过将它们的值传递给compareTo
函数来比较它们.由于它读取元素,因此列表充当生产者,因此第一部分 - 生产者扩展.这一点很明显,那么消费者超级部分呢?
Consumer Super基本上意味着如果你只是将值传递给某个函数,你并不关心它是否接受你的对象的确切类型或它的某些超类.所以binarySearch
声明所说的是:只要可以将任何内容传递给compareTo
list元素的方法,我就可以寻找任何东西.
在排序的情况下,它并不那么明显,因为元素只是相互比较.但即便如此,如果Base
实际实现Comparable
(并进行整个比较)A
并且B
只是延伸Base
而不以任何方式触及比较?然后,你将无法的列表进行排序A
,并B
因为不落实Comparable
和Comparable
分别.每次子类化时都必须重新实现整个接口!
另一个例子:如果有人想在包含某些类甚至不扩展你的类的实例的列表上进行二进制搜索会Base
怎样?
class BaseComparable implements Comparable{ 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
作为这个二进制搜索的关键.他们只能因为这个? super T
部分而这样做.请注意,此类不知道密钥是否是一个A
或B
它因此无法实现Comparable
.
至于你的例子,我想这只是一个糟糕设计的例子.不幸的是,在没有违反PECS原则和/或限制已经有限的Java泛型功能的情况下,我认为无法阻止此类事情.