通用方法上的多个通配符使Java编译器(和我!)非常困惑 让我们先考虑一个简单的场景():

通用方法上的多个通配符使Java编译器(和我!)非常困惑 让我们先考虑一个简单的场景():,java,generics,wildcard,compiler-errors,Java,Generics,Wildcard,Compiler Errors,到目前为止还不错,但事情开始变得非常混乱(): 看起来编译器正在完成它的工作,但是我们得到了这个(): 这毫无意义!在这里,我们甚至没有尝试使用两种不同的类型,它也不会编译!将其设置为List lol和List List也会产生类似的编译错误!事实上,根据我的实验,代码编译的唯一方法是如果第一个参数是显式的nulltype(): 附录B:嵌套通配符——它们的真正含义是什么??? 进一步的调查表明,可能多个通配符与问题无关,但嵌套的通配符是混淆的根源 import java.util.*; p

到目前为止还不错,但事情开始变得非常混乱():

看起来编译器正在完成它的工作,但是我们得到了这个():

这毫无意义!在这里,我们甚至没有尝试使用两种不同的类型,它也不会编译!将其设置为
List lol
List List
也会产生类似的编译错误!事实上,根据我的实验,代码编译的唯一方法是如果第一个参数是显式的
null
type():


附录B:嵌套通配符——它们的真正含义是什么??? 进一步的调查表明,可能多个通配符与问题无关,但嵌套的通配符是混淆的根源

import java.util.*;

public class IntoTheWild {

    public static void main(String[] args) {
        List<?> list = new ArrayList<String>(); // compiles fine!

        List<List<?>> lol = new ArrayList<List<String>>(); // DOES NOT COMPILE!!!
            // Type mismatch: cannot convert from
            // ArrayList<List<String>> to List<List<?>>
    }
}
import java.util.*;
进入野外的公共课{
公共静态void main(字符串[]args){
List List=new ArrayList();//编译很好!
列表>
}
}
所以它看起来可能是一个
列表
不是一个
列表
,它看起来不像任何
列表
是一个
列表makeItWild(列表列表){
返回列表;//编译很好!
}
静态列表>
}
}
于是,一个新的问题出现了:什么是
列表
  • 不应接受带有泛型的参数。在
    LOLUnknowns1b
    的情况下,
    null
    被接受,就好像第一个参数被键入为
    List
    。例如,它编译:

    List lol = null;
    List<String> list = null;
    probablyIllegal(lol, list);
    

    lol.add()
    需要一个类型为
    List的参数,正如附录B所示,这与多个通配符无关,而是误解了什么
    List不是专家,但我想我能理解

    让我们将您的示例更改为等效的示例,但使用更具区别的类型:

    static void probablyIllegal(List<Class<?>> x, Class<?> y) {
        x.add(y); // this compiles!! how come???
    }
    
    静态无效概率非法(列表y){
    x、 添加(y);//这是编译的!!怎么回事???
    }
    
    让我们将列表更改为[]以更具启发性:

    static void probablyIllegal(Class<?>[] x, Class<?> y) {
        x.add(y); // this compiles!! how come???
    }
    
    静态无效概率非法(类[]x,类y){
    x、 添加(y);//这是编译的!!怎么回事???
    }
    
    现在,x不是某种类型的类的数组。它是任何类型的类的数组。它可以包含一个
    和一个
    。这不能用普通类型参数表示:

    static<T> void probablyIllegal(Class<T>[] x  //homogeneous! not the same!
    
    static void probablyIllegal(类[]x//同构!不一样!
    

    Class
    是任何
    T
    Class
    的超级类型。如果我们认为一个类型是一组对象,那么set
    Class
    就是所有
    T
    Class
    集合的并集(它包括它自己吗?我不知道…)

    如果有人想深入了解常见问题:我现在就要开始了……好吧,我就在这个常见问题上。但即使这样,我也不明白为什么这不是一个bug。相关:我真的不知道我是否做得很好,但我已经试着解释为什么会是这样。所以基本上,这不是一个bug,而是一个避免在编译过程中浪费时间的功能?@Colin:找到“为什么它设计成这样?”的答案将是非常棒的。我现在正在寻找答案。+1这个解释证实了我的直觉,但比我的更具说服力:-)至于原因,我仍然觉得通用子类型保持不变是一个足够好的理由。@Colin:第19行没有什么特别之处,
    lol
    list
    的类型完全相同。
    List
    List从
    List
    T[]
    不是有效的步骤,因为数组是协变的,泛型在Java中是不变的。也就是说,
    字符串[]
    是一个
    对象[]
    ,但是
    列表
    不是
    列表
    。你说得对。但我只是想做一些类比来愚弄我们自己,让我们在直觉的层面上接受它。我不会去研究实际的类型理论。
    import java.util.*;
    
    public class LOLUnknowns1a {
        static void probablyIllegal(List<List<?>> lol, List<?> list) {
            lol.add(list); // this compiles!! how come???
        }
    
        public static void main(String[] args) {
            List<List<String>> lol = null;
            List<String> list = null;
            probablyIllegal(lol, list); // DOES NOT COMPILE!!
                // The method probablyIllegal(List<List<?>>, List<?>)
                // in the type LOLUnknowns1a is not applicable for the
                // arguments (List<List<String>>, List<String>)
        }
    }
    
    import java.util.*;
    
    public class LOLUnknowns1b {
        static void probablyIllegal(List<List<?>> lol, List<?> list) {
            lol.add(list); // this compiles!! how come???
        }
    
        public static void main(String[] args) {
            List<String> list = null;
            probablyIllegal(null, list); // compiles fine!
                // throws NullPointerException at run-time
        }
    }
    
    import java.util.*;
    
    public class DoubleLOL {
        static void omg2xLOL(List<List<?>> lol1, List<List<?>> lol2) {
            // compiles just fine!!!
            lol1.addAll(lol2);
            lol2.addAll(lol1);
        }
    }
    
    import java.util.*;
    
    public class IntoTheWild {
    
        public static void main(String[] args) {
            List<?> list = new ArrayList<String>(); // compiles fine!
    
            List<List<?>> lol = new ArrayList<List<String>>(); // DOES NOT COMPILE!!!
                // Type mismatch: cannot convert from
                // ArrayList<List<String>> to List<List<?>>
        }
    }
    
    import java.util.*;
    
    public class IntoTheWild2 {
        static <E> List<?> makeItWild(List<E> list) {
            return list; // compiles fine!
        }
        static <E> List<List<?>> makeItWildLOL(List<List<E>> lol) {
            return lol;  // DOES NOT COMPILE!!!
                // Type mismatch: cannot convert from
                // List<List<E>> to List<List<?>>
        }
    }
    
    List lol = null;
    List<String> list = null;
    probablyIllegal(lol, list);
    
    static void probablyIllegalAgain(List<List<? extends Number>> lol, List<? extends Integer> list) {
        lol.add(list); // compiles fine!!! how come???
    }
    
    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!!
    
    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);
        }
    }
    
        // WildSnippet1
        new HashMap<?,?>();         // DOES NOT COMPILE!!!
        new HashMap<List<?>, ?>();  // DOES NOT COMPILE!!!
        new HashMap<?, Set<?>>();   // DOES NOT COMPILE!!!
    
        // WildSnippet2
        new HashMap<List<?>,Set<?>>();            // compiles fine!
        new HashMap<Map<?,?>, Map<?,Map<?,?>>>(); // compiles fine!
    
    static void probablyIllegal(List<Class<?>> x, Class<?> y) {
        x.add(y); // this compiles!! how come???
    }
    
    static void probablyIllegal(Class<?>[] x, Class<?> y) {
        x.add(y); // this compiles!! how come???
    }
    
    static<T> void probablyIllegal(Class<T>[] x  //homogeneous! not the same!