如附录B所示,这与多个通配符无关,而是误解了List<List<?>>真正的含义。
让我们首先提醒自己,Java泛型是不变的意味着什么:
- An
Integer
is aNumber
- A
List<Integer>
is NOT aList<Number>
- A
List<Integer>
IS aList<? extends Number>
现在,我们简单地将相同的参数应用于嵌套列表情况(有关更多详细信息,请参见附录):
List<String>
is (captureable by) a List<?>
- A
List<List<String>>
is NOT (captureable by) a List<List<?>>
- A
List<List<String>>
IS (captureable by) aList<? extends List<?>>
有了这种理解,就可以解释问题中的所有片段。所以产生了困惑中(错误地)认为像一个类型
List<List<?>>可以捕获类型,如
List<List<String>>,List<List<Integer>>等,这是不正确的。
即
List<List<?>>:
是不是一个列表,其元素是某一个未知类型的列表。
…那将是一个
List<? extends List<?>>
相反,它是一个列表,其元素是ANY类型的列表。
片段
以下是说明以上几点的代码段:
List<List<?>> lolAny = new ArrayList<List<?>>();lolAny.add(new ArrayList<Integer>());lolAny.add(new ArrayList<String>());// lolAny = new ArrayList<List<String>>(); // DOES NOT COMPILE!!List<? extends List<?>> lolSome;lolSome = new ArrayList<List<String>>();lolSome = new ArrayList<List<Integer>>();
更多片段
这是有界嵌套通配符的另一个示例:
List<List<? extends Number>> lolAnyNum = new ArrayList<List<? extends Number>>();lolAnyNum.add(new ArrayList<Integer>());lolAnyNum.add(new ArrayList<Float>());// lolAnyNum.add(new ArrayList<String>()); // DOES NOT COMPILE!!// lolAnyNum = new ArrayList<List<Integer>>(); // DOES NOT COMPILE!!List<? extends List<? extends Number>> lolSomeNum;lolSomeNum = new ArrayList<List<Integer>>();lolSomeNum = new ArrayList<List<Float>>();// lolSomeNum = new ArrayList<List<String>>(); // DOES NOT COMPILE!!
回到问题
回到问题中的代码片段,以下行为符合预期(如ideone.com所示):
public class LOLUnknowns1d { static void nowDefinitelyIllegal(List<? extends List<?>> lol, List<?> list) { lol.add(list); // DOES NOT COMPILE!!! // The method add(capture#1-of ? extends List<?>) in the // type List<capture#1-of ? extends List<?>> is not // applicable for the arguments (List<capture#3-of ?>) } public static void main(String[] args) { List<Object> list = null; List<List<String>> lolString = null; List<List<Integer>> lolInteger = null; // these casts are valid nowDefinitelyIllegal(lolString, list); nowDefinitelyIllegal(lolInteger, list); }}
lol.add(list);是非法的,因为我们可能有
List<List<String>> lol和
List<Object> list。实际上,如果我们注释掉有问题的语句,则代码会编译,而这正是我们在中首次调用时所拥有的main。
问题中的所有
probablyIllegal方法都不是非法的。它们都是完全合法和类型安全的。编译器中绝对没有错误。它确实在做应该做的事情。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)