Java泛型的类型参数中的问号是什么意思?


216

这是一小段代码,摘自Stanford Parser随附的一些示例。我从事Java开发已有大约4年的时间,但是对于这种代码应该指出的内容却从未有过很深刻的了解。

List<? extends HasWord> wordList = toke.tokenize();

我不担心代码的细节。我感到困惑的是,通用表达式应该确切地用英语传达。

谁可以给我解释一下这个?


Answers:


226
? extends HasWord

表示“扩展的类/接口HasWord”。换句话说,HasWord它本身或其任何子代...基本上可以与instanceof HasWordplus 一起使用的任何东西null

用更多的技术术语来说,? extends HasWord是有界通配符,在139页有效的Java 3rd Edition的第31条中进行了介绍。有界通配符的部分是从第134页开始的第28项。

更新:由于Oracle不久前将其删除,因此PDF链接已更新。现在,它指向由伦敦玛丽皇后大学电子工程与计算机科学学院托管的副本。

更新2:让我们更详细地说明为什么要使用通配符。

如果声明一个方法的签名希望您传入List<HasWord>,则唯一可以传入的是List<HasWord>

但是,如果所说的签名是,List<? extends HasWord>那么您可以传递一个List<ChildOfHasWord>

请注意,List<? extends HasWord>和之间有细微的差别List<? super HasWord>。正如Joshua Bloch所说:PECS =生产者扩展,消费者超级。

这意味着,如果传入的是您的方法从中提取数据的集合(即,该集合正在生成供您的方法使用的元素),则应使用extends。如果您传入的是方法要向其中添加数据的集合(即该集合正在消耗您的方法创建的元素),则应使用super

这听起来可能令人困惑。但是,您可以在Listsort命令中看到它(这只是Collections.sort的两个参数版本的快捷方式)。而不是取一个Comparator<T>,实际上需要一个Comparator<? super T>。在这种情况下,比较器将使用的元素,List以便对列表本身进行重新排序。


17
“任何适用于instanceof的东西”-加上空值。请记住,对于任何checkof实例,null值都将返回false。
Eyal Schneider 2010年

12
不要忘记界面。?不必代表一个班级!
Mark Peters 2010年

9
List<HasWord>正是您所描述的:一个包含任何对象的列表,这些对象x为其x instanceof HasWord返回true,以及null。您不需要通配符。通配符意味着它实际上也可以是其他类型的列表,只要该类型是的子类型HasWord。(对于最新评论
深表歉意

1
PDF链接似乎无效,但这对我很有用:docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
user1338062 2012年

太奇怪了,去年@ user1338062发布时,我从未收到任何消息,并且不知道PDF链接不起作用。立即修复。我还添加了到书本身的链接。
Powerlord

65

问号是“任何类型”的表示。 ?单独意味着

任何扩展名Object(包括Object

而上面的例子意味着

延伸或执行任何类型 HasWord(包括HasWord如果 HasWord是一个非抽象类)


2
public Set<Class<?>> getClasses()是什么意思 有什么区别Set<Class>?我在看javax.ws.rs.core.Application
vault

14

List<? extends HasWord>接受任何扩展HasWord的具体类。如果您有以下课程...

public class A extends HasWord { .. }
public class B extends HasWord { .. }
public class C { .. }
public class D extends SomeOtherWord { .. }

... wordList只能包含As或B或两者的混合物的列表,因为这两个类都扩展了相同的父项或null(这会导致instanceof检查失败HasWorld)。


8
不仅是具体的,还是抽象的子类。
bloparod 2010年

2
不仅是具体的抽象类,还包括子接口:List<? extends Collection<String>> list = new ArrayList<List<String>>();
Mark Peters 2010年

2
实际上,您不需要通配符:List<HasWord>这样做也是如此。这里的关键是,这个变量可以包含一个List<A>List<B>以及一个List<HasWord>
圣保罗Ebermann

12

人为的“现实世界”示例可能会有所帮助。

在我的工作场所,我们有各种口味的垃圾桶。所有垃圾箱都包含垃圾,但是有些垃圾箱是专业垃圾箱,不会吸收所有类型的垃圾。所以我们有Bin<CupRubbish>Bin<RecylcableRubbish>。类型系统需要确保我不能放入HalfEatenSandwichRubbish这两种类型中的任何一种,但是可以将其放入普通的垃圾箱中Bin<Rubbish>。如果我想谈BinRubbish可以专业,所以我不能把不兼容的垃圾,那么这将是Bin<? extends Rubbish>

(注意:? extends这并不意味着是只读的。例如,我可以采取适当的预防措施,从一个未知专业的垃圾箱中取出一块垃圾,然后将其放回其他地方。)

不确定有什么帮助。存在多态性的指针对指针并不完全明显。


5

用英语讲:

List是扩展类的某种类型HasWord,包括HasWord

通常?,泛型表示任何类。并且extends SomeClass指定该对象必须扩展SomeClass(或属于该类)。


1
实际上,用type代替class。这对于接口也同样有效。
圣保罗Ebermann

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.