泛型方法上的多个通配符使Java编译器(还有我!)很迷茫

泛型方法上的多个通配符使Java编译器(还有我!)很迷茫

让我们首先考虑一个简单的场景(见ideone.com上的完整源代码):

import java.util.*;public class TwoListsOfUnknowns {
    static void doNothing(List<?> list1, List<?> list2) { }

    public static void main(String[] args) {
        List<String> list1 = null;
        List<Integer> list2 = null;
        doNothing(list1, list2); // compiles fine!
    }}

这两个通配符是不相关的,这就是为什么您可以调用doNothing带着List<String>和一个List<Integer>..换句话说,这两个?可以引用完全不同的类型。因此,以下内容不编译,这是预期的(也在ideone.com上):

import java.util.*;public class TwoListsOfUnknowns2 {
    static void doSomethingIllegal(List<?> list1, List<?> list2) {
        list1.addAll(list2); // DOES NOT COMPILE!!!
            // The method addAll(Collection<? extends capture#1-of ?>)
            // in the type List<capture#1-of ?> is not applicable for
            // the arguments (List<capture#2-of ?>)
    }}

到目前为止还不错,但事情开始变得很混乱。如ideone.com所见):

import java.util.*;public class LOLUnknowns1 {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }}

上面的代码是在Eclipse中为我编译的sun-jdk-1.6.0.17在ideone.com中,但是它应该吗?难道我们不可能List<List<Integer>> lol和一个List<String> list,类似的两个不相关的通配符情况TwoListsOfUnknowns?

实际上,以下对这个方向的轻微修改并不是编译的,这是预期的(如ideone.com所见):

import java.util.*;public class LOLUnknowns2 {
    static void rightfullyIllegal(
            List<List<? extends Number>> lol, List<?> list) {

        lol.add(list); // DOES NOT COMPILE! As expected!!!
            // The method add(List<? extends Number>) in the type
            // List<List<? extends Number>> is not applicable for
            // the arguments (List<capture#1-of ?>)
    }}

所以看起来编译器正在做它的工作,但是我们得到了这个(如ideone.com所见):

import java.util.*;public class LOLUnknowns3 {
    static void probablyIllegalAgain(
            List<List<? extends Number>> lol, List<? extends Number> list) {

        lol.add(list); // compiles fine!!! how come???
    }}

再一次,我们可能有List<List<Integer>> lol和一个List<Float> list所以这不应该编译,对吧


慕斯王
浏览 410回答 3
3回答

互换的青春

不是专家,但我想我能理解。让我们将您的示例更改为类似的内容,但使用更有区别的类型:static&nbsp;void&nbsp;probablyIllegal(List<Class<?>>&nbsp;x,&nbsp;Class<?>&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;x.add(y);&nbsp;//&nbsp;this&nbsp;compiles!!&nbsp;how&nbsp;come???}让我们把清单改为[],以便更有启发性:static&nbsp;void&nbsp;probablyIllegal(Class<?>[]&nbsp;x,&nbsp;Class<?>&nbsp;y)&nbsp;{ &nbsp;&nbsp;&nbsp;&nbsp;x.add(y);&nbsp;//&nbsp;this&nbsp;compiles!!&nbsp;how&nbsp;come???}现在,x是不一列一些班级类型。它是一个数组任何班级类型。它可以包含一个Class<String>&nbsp;和&nbsp;a&nbsp;Class<Int>..这不能用普通类型参数表示:static<T>&nbsp;void&nbsp;probablyIllegal(Class<T>[]&nbsp;x&nbsp;&nbsp;//homogeneous!&nbsp;not&nbsp;the&nbsp;same!Class<?>是一种超级类型的Class<T>为任何&nbsp;T..如果我们认为类型是一组对象,&nbsp;集&nbsp;Class<?>是所有人的联合集的Class<T>为所有人T..(它包括它自己吗?我不知道.)
打开App,查看更多内容
随时随地看视频慕课网APP