虽然f1编译,非常相似f2不会,我只是无法解释原因.(在Intellij 9和Eclipse 3.6上测试过)
而且我真的以为我已经完成了这样的问题.
import java.util.*;
public class Demo {
public List<? extends Set<Integer>> f1(){
final List<HashSet<Integer>> list = null;
return list;
}
public List<List<? extends Set<Integer>>> f2(){
final List<List<HashSet<Integer>>> list = null;
return list;
}
}
Run Code Online (Sandbox Code Playgroud)
Lau*_*ves 11
List<List<HashSet<Integer>>>是不能分配给List<List<? extends Set<Integer>>>出于同样的原因List<HashSet<Integer>>将不会分配给List<Set<Integer>>.
你可以通过更改它来编译它:
public List<List<? extends Set<Integer>>> f2(){
Run Code Online (Sandbox Code Playgroud)
进入这个:
public List<? extends List<? extends Set<Integer>>> f2(){
Run Code Online (Sandbox Code Playgroud)
你的代码没有编译的原因,以及为什么我给出的另一个例子(即:" List<HashSet<Integer>>不能赋予List<Set<Integer>>")是Java泛型不是协变的.
典型的例子是,即使Circle延伸Shape,List<Circle>并没有延长List<Shape>.如果确实如此,则List<Circle>需要有一个add(Shape)接受Square对象的方法,但显然你不希望能够向Square对象添加对象List<Circle>.
当您使用通配符时,您将获得一个切掉某些方法的类型.List<? extends Shape>保留返回的方法E,但它没有任何E作为参数的方法.这意味着你仍然有E get(int)方法,但add(E)已经消失了.List<? extends Shape>是一个超级型List<Shape>以及List<Circle>,List<? extends Circle>等.(? super通配符切片的其他方式:即方法返回类型参数的值被删除)
您的示例更复杂,因为它具有嵌套的类型参数,但归结为同样的事情:
List<HashSet<Integer>> 是一个子类型 List<? extends Set<Integer>>List<...>)中会产生一对不再具有子/超类型关系的类型.也就是说,List<List<HashSet<Integer>>>是不是一分型List<List<? extends Set<Integer>>>List<...>你包裹而不是包装你List<? extends ...>最终会保留原始关系.(这只是一个经验法则,但它可能涵盖了80%你想要使用通配符的情况.)请注意,trashgod和BalusC都是正确的,因为您可能不希望返回这种奇怪的类型.List<List<Set<Integer>>>将是一个更正常的返回类型使用.只要你始终使用集合接口而不是具体的集合类作为类型参数,这应该可以正常工作.例如:你不能将a分配List<ImmutableSet<Integer>>给a List<Set<Integer>>,但你可以将ImmutableSet<Integer>实例放入a中List<Set<Integer>>,所以永远不要List<ImmutableSet<Integer>>说List<Set<Integer>>.
" 不要使用通配符类型作为返回类型.它不会为用户提供额外的灵活性,而是迫使他们在客户端代码中使用通配符类型." - Joshua Bloch,Effective Java Second Edition,第5章,第28项.
| 归档时间: |
|
| 查看次数: |
1259 次 |
| 最近记录: |