我是一名新的java学习者。最近我正在阅读Generic编程,让我对此感到困惑......
A<T extends B> and A<? extends B>
答案 0 :(得分:18)
首先,这些是在不同环境中使用的完全不同的结构。
A<T extends B>
是泛型类型声明的一部分,例如
public class A<T extends B> { ... }
它声明了类型参数为A
的泛型类型T
,并在T
上引入了一个限制,因此T
必须是B
的子类型。
A<? extends B>
是带有通配符的参数化类型,它可以在变量和方法声明等中用作普通类型:
A<? extends B> a = ...;
public void foo(A<? extends B> a) { ... }
A<? extends B> a
之类的变量声明表示a
的类型A
参数化为B
的某个子类型。
例如,鉴于此声明
List<? extends Number> l;
你可以:
将List
的某个子类型的Number
分配给l
:
l = new ArrayList<Integer>();
从该列表中获取Number
类型的对象:
Number n = l.get(0);
但是,由于您不知道列表的实际类型参数,因此无法将任何内容放入列表l
中:
Double d = ...;
l.add(d); // Won't compile
答案 1 :(得分:8)
?
就是所谓的wildcard。它意味着任何扩展B的东西。
当您撰写List<T extends String>
时,您的List
只能包含T
类型的元素。
当您撰写List<? extends String>
时,您的List
可以包含extends String
我希望我很清楚,因为这些概念很复杂。
答案 2 :(得分:5)
(长篇评论,不是答案)
完全不同的东西。语法的相似性是Java造成的严重错误。而这个错误导致了更大的错误 - 许多人试图将通配符理解为类型参数(即通配符捕获)
在Java发明它之前,没有A<? extends B>
这样的东西。在那之前,研究人员使用的语法是A<B+>
。 Java认为这对我们糟糕的程序员来说太神秘了,所以它发明了第一轮似乎读得更好的语法A<? extends B>
。
嗯,这是多么冗长和丑陋。如果API有一些通配符,它看起来像符号的呕吐物。
但最糟糕的是它引起的混乱。它看起来像一个类型参数。 Java是故意这样做的! Java并不相信它的程序员可以理解协变类型,所以语法上它使得可变类型看起来像参数化类型,引导程序员进入错误的理解方式,不可否认,这在某些场合很有用,但最终会让人无能为力
答案 3 :(得分:3)
泛型是一个复杂的主题,特别是在Java中。但基本上区别在于:
存在特定类型T,它仅限于B或B的子类,但它是特定的知识类型。任何普通的旧通用声明都是这样说的:<T extends Object>
通过说T扩展B,我们说T比任何对象更有限,它必须特别是B的类型。 / p>
这意味着泛型类型是未知的,确切地说,但我们可以说它是扩展B.它可能是B,它可能是B的子类。带有通配符和单词extends,它意味着你可以从对象中获取B,但是你不能以类型安全的方式在对象中放置任何东西。 (?super B意味着相反 - 你可以把一些东西放在B的B或B的超类中,但你不能确定方法的返回值是什么。)