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

为什么这个简单的Java泛型函数不能编译?,java,generics,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; retu

虽然
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;         
    } 

}
import java.util.*;
公开课演示{

公共列表
列表
不可分配给
列表“不要将通配符类型用作返回类型。它会强制用户在客户端代码中使用通配符类型,而不是为用户提供额外的灵活性。”-Joshua Bloch,第5章,第28项。

这太长了,无法用于评论。我只是想说,这样声明没有任何意义。您也可以执行以下操作:

public List<List<Set<Integer>>> f2() {
    List<List<Set<Integer>>> list = new ArrayList<List<Set<Integer>>>();
    List<Set<Integer>> nestedList = new ArrayList<Set<Integer>>();
    list.add(nestedList);
    Set<Integer> set = new HashSet<Integer>();
    nestedList.add(set);
    return list;
}
这可以通过将接口(
Set
在本例中)而不是实现(
HashSet
在本例中)声明为泛型类型来解决。因此:

public List<Map<Integer, Set<Integer>>> getOutcomes() {
    Map<Set<Integer>, Integer> map = new HashMap<Set<Integer>, Integer>();
    List<Map<Integer, Set<Integer>>> outcomes = new ArrayList<Map<Integer, Set<Integer>>>();
    for (Map.Entry<Set<Integer>, Integer> entry : map.entrySet()) {
        outcomes.add(asMap(entry.getValue(), entry.getKey()));
        // add() now compiles fine.
    }
    return outcomes;
}
public List getoutcouts(){
Map Map=newhashmap();
列表结果=新的ArrayList();
对于(Map.Entry:Map.entrySet()){
add(asMap(entry.getValue(),entry.getKey());
//add()现在可以正常编译。
}
回报结果;
}

在未来的问题中,试着问如何解决一个特定的问题,而不是如何实现一个特定的解决方案(这可能不是正确的解决方案).

找到不兼容的类型:java.util.List required:java.util.List为什么不在所有位置使用
List
?这也是正常的方法。您希望声明接口,而不是实现。正在尝试在该列表中添加com.google.common.collect.ImmutableSet。"出于同样的原因,列表将不可分配给List@lacroix1547:不,我没有随机尝试不同的东西。我会在答案中添加更多细节。列表是列表的一个子类型。这只是一个深入的私有方法,不是任何api的一部分。这是合理的。我无意显得挑剔;我只是想引用这个原则。+1,一个非常重要的原则我知道,但它解决了import Java.util.*;公共类Demo2{public List getoutlets(){Map Map Map=new HashMap();List outlets=new ArrayList();for(Map.Entry:Map.entrySet()){outlets.add(asMap(Entry.getValue(),Entry.getKey());}返回结果;}公共映射asMap(kk,vv){Map result=new HashMap();result.put(K,V);return result;}}我现在就去读劳伦斯的协变函数,也许它会让我明白。你总是把实现而不是接口声明为泛型类型。例如,替换
Map=new HashMap();
by
Map=newhashmap()
。是的,我试图保留实现,它实际上是一个ImmutableSet,看看会发生什么。如果可以的话,我很高兴看到ImmutableSet而不是Set。它是实验性的,也不是主要主题。@lacroix1547:将您的代码发布到pastebin.com,然后在评论中添加一个链接。
public List<List<Set<Integer>>> f2() {
    List<List<Set<Integer>>> list = new ArrayList<List<Set<Integer>>>();
    List<Set<Integer>> nestedList = new ArrayList<Set<Integer>>();
    list.add(nestedList);
    Set<Integer> set = new HashSet<Integer>();
    nestedList.add(set);
    return list;
}
public List<Map<Integer, Set<Integer>>> getOutcomes() {
    Map<HashSet<Integer>, Integer> map = new HashMap<HashSet<Integer>, Integer>();
    List<Map<Integer, Set<Integer>>> outcomes = new ArrayList<Map<Integer, Set<Integer>>>();
    for (Map.Entry<HashSet<Integer>, Integer> entry : map.entrySet()) {
        outcomes.add(asMap(entry.getValue(), entry.getKey())); 
        // add() gives compiler error: The method add(Map<Integer,Set<Integer>>)
        // in the type List<Map<Integer,Set<Integer>>> is not applicable for 
        // the arguments (Map<Integer,HashSet<Integer>>)
    }
    return outcomes;
}

public <K, V> Map<K, V> asMap(K k, V v) {
    Map<K, V> result = new HashMap<K, V>();
    result.put(k, v);
    return result;
}
public List<Map<Integer, Set<Integer>>> getOutcomes() {
    Map<Set<Integer>, Integer> map = new HashMap<Set<Integer>, Integer>();
    List<Map<Integer, Set<Integer>>> outcomes = new ArrayList<Map<Integer, Set<Integer>>>();
    for (Map.Entry<Set<Integer>, Integer> entry : map.entrySet()) {
        outcomes.add(asMap(entry.getValue(), entry.getKey()));
        // add() now compiles fine.
    }
    return outcomes;
}