我有:
class Document { ... }
class DocumentCluster extends Document { ... }
我正试图用这种方式定义一组文档:
Set<? extends Document> docs = new HashSet<Document>();
但是,当我尝试将文档插入到我的设置中时:
docs.add(d);
我得到了:
The method add(capture#10-of ? extends Document) in the type Set<capture#10-of ? extends Document> is not applicable for the arguments (Document)
我做错了什么?
答案 0 :(得分:5)
因为它可能只允许B
类型的对象。
一个经典的问题,回答了一百万次。非直观,但也不是Java的设计缺陷。
以下是经典示例:让A
成为Fruit
。
我可以将Apple
加入Set<? extends Fruit>
吗?
否,因为它可能是Set<Banana>
,显然不得包含苹果。
? extends Fruit
说一些特定类型的水果,不“任何种类的水果”。然后它将是Set<Fruit>
,它确实可以采取任何种类的水果。
根据经验:
? super Fruit
方便。这需要“至少”水果? extends Fruit
很方便。它可能只返回一种水果,但它们都是水果。考虑这种方法:
public static double computeAverage(Collection<? extends Number> col) {
double sum = 0.;
for (Number n : col) {
sum += n.doubleValue();
}
return sum / n.size();
}
此方法可以与List<Integer>
一起使用。因为它不将Double
放入列表中,但只将Number
个对象取出。
public static void put(Collection<? super Number> col, Number n) {
col.put(n);
}
在这里,我们有相反的情况。我们需要一个接受任意数字的列表(否则,我们无法将非特定数字放入其中)。但是,它可能会接受更多:
put(new List<Object>(), (Double) 1.);
是有效的,因为我可能将双打放入对象列表中。
但编译器正确会阻止put( new List<Integer>(), (Double) 1.)
。
它可能比那更麻烦:
public static <I,O> void transfer(Collection<? extends I> input,
Collection<? super O> output,
Converter<? super I, ? extends O> converter) {
for (I inobj : input) {
O outobj = converter.convert(inobj);
output.put(outobj);
}
}
但是编译器可能无法每次为您自动找出I
和O
。
答案 1 :(得分:0)
Set<? extends A>
,因为您没有准确添加到集合的类型,只是添加了扩展A的SOMETHING。您可以保证使用{{1}时你会得到一个扩展A的类,但是当你使用get()
因为你不知道确定类型时,就无法添加到集合中
如果您想利用多态性,请使用add()
。这将完全相同 - 任何类型兼容的成员,即Set<A>
的扩展名,都可以放在A
中。
编辑: @ Anony-Mousse用一个例子更好地解释了这一点。