这些类声明与Comparable有什么区别?

时间:2015-02-21 20:15:07

标签: java generics tree comparable generic-programming

这是一个声明

public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
   ....
}

这是另一个宣言

public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
    .....
}

我知道第一个声明是首选(在很多java示例和教科书中看到它),但为什么会这样?当我尝试使用第二个声明时,我的所有代码都运行良好。

我知道在这种情况下超级使用了吗? super AnyType,表示AnyType或其任何超类。 Super

对我来说,两个人都说这个类BinarySearchTree支持任何可比较的对象类型。任何人都可以描述或举例说明这种微妙的差异实际上会产生什么影响吗?

以狗为例

class Animal implements Comparable<Animal>
class Dog extends Animal
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
  ...}
Would allow for  
BinarySearchTree<Dog> but 
 public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
    .....
} wouldn't

2 个答案:

答案 0 :(得分:3)

  

任何人都可以描述或举例说明这种微妙的差异实际上会产生什么影响吗?

是。 JDK的两个例子:

你会注意到后者扩展了前者,但{s} Date实现的是Comparable的{​​{1}}。

如果它“仅”实施java.util.Date,那么您将无法将其与“正常”Comparable进行比较。

还要考虑Date的简单情况(Java 8中出现的界面)。最常用的ConsumerConsumer;在这种情况下,它的参数是System.out::println

现在,如果Object Stream的签名是.forEach()而不是.forEach(Consumer<T> consumer),那么您根本无法使用“普遍消费者” ,除了.forEach(Consumer<? super T>) s!

这是PECS规则的CS部分(Producer Extends,Consumer Super)。

答案 1 :(得分:2)

如果你有

class Animal implements Comparable<Animal>
class Dog extends Animal

然后BinarySearchTree<Dog>与第一个签名合法,但与第二个签名不合法。第二个签名不合法,因为Dog没有实现Comparable<Dog>(并且没有办法让它实现Comparable<Dog>,因为它已经实现了Comparable<Animal>和一个类型无法实现具有两个不同类型参数的接口。)

如果您考虑一下,BinarySearchTree<Dog>完全正常,因为Dog与自己相当(实际上它们与所有Animal相当,其中包括所有Dog } S)。我们所需要的只是保证someDog.compareTo(someOtherDog)有效。为了实现这一点,我们不需要compareTo完全采用Dog - Dog的任何超类型也可以。这就是? super所代表的含义。它放松了对更一般的约束,仍然提供我们需要的所有类型保证。在泛型中,我们应该始终使用限制性最小的界限来为我们提供所需的类型安全性。

另一种思考方式是通过PECS规则(Producer extends,Consumer super)。 Comparable<T>只能是T的“使用者”,因为其唯一方法采用T类型的参数,并且不会返回T。因此,Comparable应始终与? super ...通配符一起使用。