3

每次我认为我更好地理解泛型(并且可以在不编译的情况下回答)时,我都会遇到一个这个理论被打破的例子。这是一个非常简单的例子:

static void consumer(List<? super List<String>> param) {
    System.out.println(param);
}

和两个调用:

public static void main(String[] args) {
    List<String> list = List.of("123");
    consumer(list);
    consumer(List.of("123"));
}

对我来说,任何调用都不应该编译。AString不是 的超类型List。尽管如此,第二个编译。但是让我们假设发生这种情况是因为编译器可以在这里推断出某种类型。当然这样的类型不存在,它会在运行时失败,对吧?对?没有。它只是工作。因此,有人可以给我的生活带来一些理智吗?

4

2 回答 2

9

啊该死!

javac  --debug=verboseResolution=all Sandbox.java

显示consumer(List.of("123"))编译为:

instantiated signature: (Object)List<Object>
target-type: List<? super List<String>>
于 2020-10-23T04:02:09.143 回答
2

如果你想要一个更“<em>功能”的解释,你必须考虑什么param是。

通过应用PECS,请注意它是List的消费者List<String>

  • 兼容的消费者是那些可以消费的消费者List<String>或其任何父类型;
  • 当应用于 时List,它表示您可以add()使用任何父类型调用的列表List<String>。因此AList<Object>是兼容的。

这就是为什么consumer()可以用 aList<Object>而不是 a List<String>(String不是List<String>) 的超类型来调用的原因。

由于List.of(…)可以在声明时始终匹配List<Object>,因此它接受第二次调用。

请注意,从consumer()方法内部,您将永远无法从中检索 a List<String>param即,将其用作生产者)。您只能将新的添加到其中(即,将其用作消费者)——实际上,您可以将 a 添加List<String>到 aList<Object>中(尽管在这种特殊情况下,List.of()会生成一个不可变列表,因此它将在运行时失败)。

于 2020-10-29T12:37:41.910 回答