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