Java泛型不可能赋值?

问题描述

每当我思考时,我都会更好地理解泛型(并且无需编译即可回答),我得到了一个打破这一理论的例子。这是一个非常简单的示例:

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

对我来说,任何调用都不应该编译。 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()方法内部,您将永远无法从List<String>中检索param(即,将其用作生产者)。您只能在其中添加新的(即,将其用作使用者)–实际上,您可以在List<String>中添加List<Object>(尽管在这种情况下,List.of()会产生一个不可变的列表,因此它将在运行时失败。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...