首页 > Java > java教程 > 为什么 List> 允许不同类型的嵌套列表?

为什么 List> 允许不同类型的嵌套列表?

Patricia Arquette
发布: 2024-11-18 21:38:02
原创
1012 人浏览过

Why Does a List<List<?>> 允许不同类型的嵌套列表吗? 
> 允许不同类型的嵌套列表? " />

泛型方法上的多个通配符可能会混淆 Java 编译器

问题:

在泛型方法可能会导致 Java 编译器和程序员感到困惑,请考虑以下内容。示例:

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!
    }
}
登录后复制

两个不相关的通配符可用于通过 List 和 List 调用 doNothing,但是以下变体无法编译:

public class TwoListsOfUnknowns2 {
    static void doSomethingIllegal(List<?> list1, List<?> list2) {
        list1.addAll(list2); 
            // DOES NOT COMPILE!!!
    }
}
登录后复制
这种行为是预期的,因为 list1 和 list2 引用完全不同的类型。

会产生混淆以下代码:

public class LOLUnknowns1 {
    static void probablyIllegal(List<List<?>> lol, List<?> list) {
        lol.add(list); // this compiles!! how come???
    }
}
登录后复制
该代码可以编译,但可以有一个 List> 哈哈,下面的修改列表不应该吗?代码无法编译?

public class LOLUnknowns2 {
    static void rightfullyIllegal(
            List<List<? extends Number>> lol, List<?> list) {

        lol.add(list); // DOES NOT COMPILE! As expected!!!
    }
}
登录后复制
编译器似乎正在完成其工作,但以下内容仍然存在混乱变体:

public class LOLUnknowns3 {
    static void probablyIllegalAgain(
            List<List<? extends Number>> lol, List<? extends Number> list) {

        lol.add(list); // compiles fine!!! how come???
    }
}
登录后复制
这段代码不应该编译吗,因为它可能涉及一个 List> lol 和一个 List 列表?

澄清这些行为,让我们将代码简化回 LOLUnknowns1 并尝试调用可能非法:

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!!
    }
}
登录后复制
即使两个通配符的类型相同,代码也无法编译。然而,第一个参数为空类型编译:

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!
    }
}
登录后复制

答案:

混乱源于对嵌套通配符的误解,例如 List< ;列表>,实际上是这个意思。 Java 泛型是不变的,这意味着类型之间的关系不适用于泛型实例化。这也适用于嵌套列表:

A 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) a List<? extends List<?>>.
登录后复制
因此,List>>表示一个列表,其元素是任何类型的列表,而不是特定的同一类型。这意味着以下代码是合法的:

List<List<?>> lolAny = new ArrayList<>();

lolAny.add(new ArrayList<Integer>());
lolAny.add(new ArrayList<String>());
登录后复制

总结

Java 编译器使用多个通用通配符的行为由捕获转换规则确定。了解通配符捕获的局限性对于避免混淆至关重要。

以上是为什么 List> 允许不同类型的嵌套列表?的详细内容。更多信息请关注PHP中文网其他相关文章!

来源:php.cn
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
作者最新文章
热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板