Java 泛型不可能赋值?

Java generics impossible assignment?

每次我 认为 我更好地理解泛型(并且无需编译就可以回答),我得到一个这个理论被打破的例子。这是一个非常简单的例子:

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"));
}

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

啊该死!

javac  --debug=verboseResolution=all Sandbox.java

表明consumer(List.of("123"))被编译为:

instantiated signature: (Object)List<Object>
target-type: List<? super List<String>>

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

通过应用 PECS,请注意因此 ListList<String> 的消费者。

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

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

由于List.of(…)在声明时总能匹配List<Object>,它接受第二次调用。

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