【发布时间】:2010-06-09 20:38:22
【问题描述】:
这是从斯坦福解析器附带的一些示例中提取的一小段代码。我已经使用 Java 进行了大约 4 年的开发,但从未对这种代码风格应该表示什么有非常深刻的理解。
List<? extends HasWord> wordList = toke.tokenize();
我不担心代码的细节。我感到困惑的是,通用表达式到底应该用英语表达什么。
谁能给我解释一下?
【问题讨论】:
这是从斯坦福解析器附带的一些示例中提取的一小段代码。我已经使用 Java 进行了大约 4 年的开发,但从未对这种代码风格应该表示什么有非常深刻的理解。
List<? extends HasWord> wordList = toke.tokenize();
我不担心代码的细节。我感到困惑的是,通用表达式到底应该用英语表达什么。
谁能给我解释一下?
【问题讨论】:
? 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 本身。
【讨论】:
List<HasWord> 正是您所描述的:包含x 的任何对象的列表,x instanceof HasWord 为其返回 true,null。为此,您不需要通配符。通配符意味着它实际上也可以是另一种类型的列表,只要这种类型是HasWord 的子类型。 (对不起,迟到的评论。)
问号是“任何类型”的符号。 ?单独表示
任何扩展
Object的类型(包括Object)
而你上面的例子意味着
任何扩展或实现的类型
HasWord(包括HasWord如果HasWord是一个非抽象类)
【讨论】:
public Set<Class<?>> getClasses() 是什么意思?与Set<Class> 有什么区别?我在看javax.ws.rs.core.Application。
Set<Class> 是一组 raw 类。 <?> 是隐含的
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>。
也许一个人为的“真实世界”示例会有所帮助。
在我工作的地方,我们有不同口味的垃圾桶。所有垃圾箱都包含垃圾,但有些垃圾箱是专业的,不会收集所有类型的垃圾。所以我们有Bin<CupRubbish> 和Bin<RecylcableRubbish>。类型系统需要确保我不能将我的HalfEatenSandwichRubbish 放入这些类型中的任何一种,但它可以进入一般的垃圾箱Bin<Rubbish>。如果我想谈谈Rubbish 中的Bin 可能是专门的,所以我不能放入不兼容的垃圾,那么那就是Bin<? extends Rubbish>。
(注意:? extends 并不意味着只读。例如,我可以通过适当的预防措施从一个未知专业的垃圾箱中取出一块垃圾,然后将其放回不同的地方。)
不确定这有多大帮助。 存在多态性的指针对指针并不完全明显。
【讨论】:
英文:
这是一个扩展类
HasWord的某种类型的List,包括HasWord
一般来说,泛型中的? 表示任何类。而extends SomeClass 指定该对象必须扩展SomeClass(或者是那个类)。
【讨论】:
问号用于定义通配符。查看有关它们的 Oracle 文档:http://docs.oracle.com/javase/tutorial/java/generics/wildcards.html
【讨论】: