为什么这个简单的Java泛型函数不能编译?

lac*_*547 5 java generics

虽然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>>.


tra*_*god 6

" 不要使用通配符类型作为返回类型.它不会为用户提供额外的灵活性,而是迫使他们在客户端代码中使用通配符类型." - Joshua Bloch,Effective Java Second Edition,第5章,第28项.

  • 那是合理的.我的意思并不是看起来很苛刻; 我只是想引用这个原则. (2认同)