Java泛型的类型参数中的问号是啥意思? [复制]
Posted
技术标签:
【中文标题】Java泛型的类型参数中的问号是啥意思? [复制]【英文标题】:What does the question mark in Java generics' type parameter mean? [duplicate]Java泛型的类型参数中的问号是什么意思? [复制] 【发布时间】:2010-06-09 20:38:22 【问题描述】:这是从斯坦福解析器附带的一些示例中提取的一小段代码。我已经使用 Java 进行了大约 4 年的开发,但从未对这种代码风格应该表示什么有非常深刻的理解。
List<? extends HasWord> wordList = toke.tokenize();
我不担心代码的细节。我感到困惑的是,通用表达式到底应该用英语表达什么。
谁能给我解释一下?
【问题讨论】:
bayou.io/draft/Capturing_Wildcards.html 【参考方案1】:? extends HasWord
表示“扩展HasWord
的类/接口。”换句话说,HasWord
本身或它的任何孩子......基本上任何可以与instanceof HasWord
加上null
一起使用的东西。
在更专业的术语中,? extends HasWord
是一个有界通配符,在 Effective Java 3rd Edition 的第 31 项中介绍,从第 139 页开始。第 2 版的同一章节是 available online as a PDF;有界通配符部分是从第 134 页开始的第 28 项。
更新:PDF 链接已更新,因为 Oracle 不久前将其删除。它现在指向伦敦玛丽女王大学电子工程与计算机科学学院主办的副本。
更新 2:让我们更详细地说明为什么要使用通配符。
如果您声明一个方法,其签名希望您传入List<HasWord>
,那么您唯一可以传入的就是List<HasWord>
。
但是,如果所述签名是 List<? extends HasWord>
,那么您可以传入 List<ChildOfHasWord>
。
请注意,List<? extends HasWord>
和 List<? super HasWord>
之间存在细微差别。正如 Joshua Bloch 所说:PECS = producer-extends,consumer-super。
这意味着如果您传入一个集合,您的方法从中提取数据(即该集合正在生成供您的方法使用的元素),您应该使用extends
。如果您要传入您的方法添加数据的集合(即该集合正在使用您的方法创建的元素),则应使用super
。
这听起来可能令人困惑。但是,您可以在 List
的 sort
命令中看到它(这只是 Collections.sort 的双参数版本的快捷方式)。它实际上没有采用Comparator<T>
,而是采用Comparator<? super T>
。在这种情况下,Comparator 正在使用 List
的元素以重新排序 List 本身。
【讨论】:
"任何可以与 instanceof 一起使用的东西" - 加上空值。请记住,对于任何 instanceof 检查,null 值都会返回 false。 不要忘记接口。这 ?不必代表一个类!List<HasWord>
正是您所描述的:包含x
的任何对象的列表,x instanceof HasWord
为其返回 true,null
。为此,您不需要通配符。通配符意味着它实际上也可以是另一种类型的列表,只要这种类型是HasWord
的子类型。 (对不起,迟到的评论。)
PDF 链接似乎不起作用,但这对我很有用:docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
这很奇怪,去年当@user1338062 发布并且不知道 PDF 链接不起作用时,我从未收到过消息。现在修好了。我还添加了本书本身的链接。【参考方案2】:
问号是“任何类型”的符号。 ?
单独表示
任何扩展
Object
的类型(包括Object
)
而你上面的例子意味着
任何扩展或实现的类型
HasWord
(包括HasWord
如果HasWord
是一个非抽象类)
【讨论】:
那么public Set<Class<?>> getClasses()
是什么意思?与Set<Class>
有什么区别?我在看javax.ws.rs.core.Application
。
@vault Set<Class>
是一组 raw 类。 <?>
是隐含的【参考方案3】:
List<? extends HasWord>
接受任何扩展 HasWord 的具体类。如果你有以下课程...
public class A extends HasWord ..
public class B extends HasWord ..
public class C ..
public class D extends SomeOtherWord ..
...wordList
只能包含 As 或 Bs 或两者的混合列表,因为这两个类都扩展了相同的父级或 null
(它无法通过实例检查 HasWorld
)。
【讨论】:
不仅是具体的,还有抽象的子类。 不仅有具体的和抽象的子类,还有子接口:List<? extends Collection<String>> list = new ArrayList<List<String>>();
.
实际上,您不需要通配符:List<HasWord>
也可以做到这一点。这里的重点是这个变量可以包含List<A>
或List<B>
以及List<HasWord>
。【参考方案4】:
也许一个人为的“真实世界”示例会有所帮助。
在我工作的地方,我们有不同口味的垃圾桶。所有垃圾箱都包含垃圾,但有些垃圾箱是专业的,不会收集所有类型的垃圾。所以我们有Bin<CupRubbish>
和Bin<RecylcableRubbish>
。类型系统需要确保我不能将我的HalfEatenSandwichRubbish
放入这些类型中的任何一种,但它可以进入一般的垃圾箱Bin<Rubbish>
。如果我想谈谈Rubbish
中的Bin
可能是专门的,所以我不能放入不兼容的垃圾,那么那就是Bin<? extends Rubbish>
。
(注意:? extends
并不意味着只读。例如,我可以通过适当的预防措施从一个未知专业的垃圾箱中取出一块垃圾,然后将其放回不同的地方。)
不确定这有多大帮助。 存在多态性的指针对指针并不完全明显。
【讨论】:
【参考方案5】:英文:
这是一个扩展类
HasWord
的某种类型的List
,包括HasWord
一般来说,泛型中的?
表示任何类。而extends SomeClass
指定该对象必须扩展SomeClass
(或者是那个类)。
【讨论】:
其实是type而不是class。这同样适用于接口。【参考方案6】:问号用于定义通配符。查看有关它们的 Oracle 文档:http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
【讨论】:
以上是关于Java泛型的类型参数中的问号是啥意思? [复制]的主要内容,如果未能解决你的问题,请参考以下文章