在学习 Java8 Streams 时,我遇到了以下代码片段:
Predicate<? super String> predicate = s -> s.startsWith("g");
由于通用参数是下限,我认为这不会编译。在我看来,如果一个对象是一个字符串的超类型,那么传入一个对象类型应该会破坏它,因为对象没有startsWith()函数。然而,我很惊讶地发现它没有任何问题地工作。
此外,当我调整谓词以取上限时:
<? extends String>,
它不会编译。
我以为我理解了上限和下限的含义,但显然,我错过了一些东西。任何人都可以帮助解释为什么下限适用于这个 lambda 吗?
Lambda 参数类型是精确的,但不能是? super
or ? extends
。这涵盖了JLS 15.27.3。 Lambda 表达式的类型 https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.27。它介绍了地面目标类型概念(基本上是 lambda 类型)。除其他事项外,还指出:
If T
是通配符参数化函数接口类型并且 lambda 表达式是隐式类型的,那么基本目标类型是非通配符参数化 (§9.9 https://docs.oracle.com/javase/specs/jls/se8/html/jls-9.html#jls-9.9) of T.
强调我的。所以本质上当你写的时候
Predicate<? super String> predicate = s -> s.startsWith("g");
你的 lambda 类型是Predicate<String>
。它等同于:
Predicate<? super String> predicate = (Predicate<String>)(s -> s.startsWith("g"));
Or even
Predicate<String> pred = (Predicate<String>)(s -> s.startsWith("g"));
Predicate<? super String> predicate = pred;
考虑到 lambda 类型参数是具体的,之后应用正常的类型转换规则:Predicate<String>
is a Predicate<? super String>
, or Predicate<? extends String>
。所以两者Predicate<? super String>
and Predicate<? extends String>
应该编译。两者实际上都适用于 javac 8u25、8u45、8u71 以及 ecj 3.11.1。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)