> 允许不同类型的嵌套列表? " />
泛型方法上的多个通配符可能会混淆 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
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
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中文网其他相关文章!