这是从斯坦福解析器附带的一些示例中截取的一小段代码。我已经用Java开发了大约4年,但从来没有非常清楚这种风格的代码应该表示什么。

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

我不担心代码的细节。我困惑的是,在英语中,这种通用表达到底应该表达什么。

有人能给我解释一下吗?


? extends HasWord

意思是“扩展HasWord的类/接口”。换句话说,HasWord本身或它的任何子…基本上任何可以使用instanceof HasWord + null的东西。

用更专业的术语来说,?HasWord是一个有界通配符,在Effective Java 3rd Edition的第31项中介绍,从第139页开始。第二版中的同一章节在网上以PDF格式提供;关于有界通配符的部分是第134页开始的第28项。

更新:PDF链接已经更新,因为Oracle之前删除了它。它现在指向了伦敦玛丽女王大学电子工程和计算机科学学院的副本。

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

如果你声明一个方法,它的签名希望你传入List<HasWord>,那么你唯一能传入的就是List<HasWord>。

然而,如果所说的签名是List<?extends HasWord>,那么你可以传入List<ChildOfHasWord>代替。

注意,List<?扩展HasWord>和List<?超级HasWord >。正如约书亚·布洛赫所说:PECS =生产者延伸,消费者超。

这意味着,如果你传入一个你的方法从中提取数据的集合(也就是说,这个集合产生元素供你的方法使用),你应该使用extends。如果你传入一个集合,你的方法将数据添加到其中(即集合正在消耗你的方法创建的元素),它应该使用super。

这听起来可能令人困惑。但是,您可以在List的sort命令中看到它(这只是Collections.sort的双参数版本的快捷方式)。它没有取Comparator<T>,而是取Comparator<?超级T >。在这种情况下,Comparator正在消耗List的元素,以便对List本身进行重新排序。


问号表示“任何类型”。? 就意味着

任何类型的扩展对象(包括对象)

而你上面的例子意味着

任何类型的扩展或实现 HasWord(包括HasWord if HasWord是非抽象类)


英文:

它是某种类型的列表,扩展了类HasWord,包括HasWord

一般来说?在泛型中是指任何类。而extends SomeClass则指定该对象必须扩展SomeClass(或者是该类)。


列表< ?>接受任何扩展HasWord的具体类。如果你有以下课程…

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

... wordList只能包含a或b的列表,或者两者的混合,因为这两个类扩展了相同的父类或null(这在HasWorld的instanceof检查中失败)。


也许一个虚构的“现实世界”的例子会有所帮助。

At my place of work we have rubbish bins that come in different flavours. All bins contain rubbish, but some bins are specialist and do not take all types of rubbish. So we have Bin<CupRubbish> and Bin<RecylcableRubbish>. The type system needs to make sure I can't put my HalfEatenSandwichRubbish into either of these types, but it can go into a general rubbish bin Bin<Rubbish>. If I wanted to talk about a Bin of Rubbish which may be specialised so I can't put in incompatible rubbish, then that would be Bin<? extends Rubbish>.

(注:?Extends并不意味着只读。例如,在适当的预防措施下,我可以从一个不知名的特产垃圾桶里拿出一块垃圾,然后把它放回另一个地方。

不知道这有多大帮助。存在多态性的指针到指针并不完全明显。


问号用于定义通配符。签出关于它们的Oracle文档:http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html