这些 class 声明与 Comparable 之间有什么区别?
What is the difference between these class declarations with Comparable?
这是一份声明
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
....
}
这是另一个声明
public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
.....
}
我知道首选第一个声明(在很多 java 示例和教科书中都看到过)但为什么呢?当我尝试使用第二个声明时,我的所有代码 运行 都很好。
我知道在这种情况下使用了 super,? super AnyType,表示 AnyType 或其任何 super classes。 Super
对我来说,这两个 class,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
Can anyone describe or give an example of where this subtle difference actually makes a difference?
是的。来自 JDK 的两个示例:
您会注意到后者扩展了前者,但 (sql) Date
实现的是 java.util.Date
的 Comparable
。
如果它 "only" 实现了 Comparable
本身,您将无法将它与 "normal" Date
.
进行比较
还考虑了 Consumer
的简单情况(出现在 Java 8 中的接口)。其中最常用的 Consumer
是 System.out::println
;在这种情况下,它的参数是 Object
。
现在,如果 Stream
的 .forEach()
的签名是 .forEach(Consumer<T> consumer)
而不是 .forEach(Consumer<? super T>)
,您将无法使用 "universal consumer",除了 Stream<Object>
s!
这是PECS规则的CS部分(Producer Extends,Consumer Super)。
如果你有
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 规则(生产者 extends
、消费者 super
)。一个Comparable<T>
只能是T
的一个"consumer",因为它唯一的方法接受一个T
类型的参数,它不会returnT
.因此,Comparable
应始终与 ? super ...
通配符一起使用。
这是一份声明
public class BinarySearchTree<AnyType extends Comparable<? super AnyType>> {
....
}
这是另一个声明
public class BinarySearchTree<AnyType extends Comparable<AnyType>>{
.....
}
我知道首选第一个声明(在很多 java 示例和教科书中都看到过)但为什么呢?当我尝试使用第二个声明时,我的所有代码 运行 都很好。
我知道在这种情况下使用了 super,? super AnyType,表示 AnyType 或其任何 super classes。 Super
对我来说,这两个 class,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
Can anyone describe or give an example of where this subtle difference actually makes a difference?
是的。来自 JDK 的两个示例:
您会注意到后者扩展了前者,但 (sql) Date
实现的是 java.util.Date
的 Comparable
。
如果它 "only" 实现了 Comparable
本身,您将无法将它与 "normal" Date
.
还考虑了 Consumer
的简单情况(出现在 Java 8 中的接口)。其中最常用的 Consumer
是 System.out::println
;在这种情况下,它的参数是 Object
。
现在,如果 Stream
的 .forEach()
的签名是 .forEach(Consumer<T> consumer)
而不是 .forEach(Consumer<? super T>)
,您将无法使用 "universal consumer",除了 Stream<Object>
s!
这是PECS规则的CS部分(Producer Extends,Consumer Super)。
如果你有
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 规则(生产者 extends
、消费者 super
)。一个Comparable<T>
只能是T
的一个"consumer",因为它唯一的方法接受一个T
类型的参数,它不会returnT
.因此,Comparable
应始终与 ? super ...
通配符一起使用。