泛型方法上的多个通配符:Java 编译器难题
简介
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! } }
doNothing 中的两个通配符看起来不相关,允许您使用 List
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 可能是与 lol 元素不同的类型,此代码编译也不会出现错误。但是,需要注意的是,这种情况会引发有关类型安全的问题。
真相:捕获转换
这种混乱源于称为捕获转换的概念。它允许某些通配符在泛型方法中使用时捕获特定类型。这就是为什么下面的 possibleIllegal 变体可以编译:
static void probablyIllegalAgain(List<List<? extends Number>> lol, List<? extends Number> list) { lol.add(list); // compiles fine!!! how come??? }
这里,lol 中的通配符可以捕获扩展 Number 的类型,例如 List
理解嵌套通配符
关键要点是多个通配符本身没有问题。当尝试使用嵌套通配符捕获由于类型差异而不“兼容”的类型时,会出现混乱。
对于 LOLUnknowns1,List> 中的嵌套通配符是无法捕获特定类型,因为捕获对于 lol 的所有可能元素类型来说并不安全。这就是为什么 list 可以是任何类型,从而导致潜在的类型安全问题。
结论
泛型方法上的多个通配符可能会令人困惑,但了解捕获转换和它的局限性至关重要。嵌套通配符需要仔细考虑以确保类型安全。通过遵守这些原则,您可以了解 Java 泛型的复杂性并编写健壮的代码。
以上是为什么 Java 中泛型方法上的多个通配符会导致混乱?的详细内容。更多信息请关注PHP中文网其他相关文章!