捕获 Java 中的转换问题,JLS 和实际 JDK 行为的 WRT 协调

Capture conversion issue in Java, WRT reconciliation of JLS and actual JDK behaviour

给定以下两个 class 定义:

class C1<T extends C1<T>> {}

class C2<U> extends C1<C2<U>> {}

考虑以下类型声明:

C1<? extends C2<String>> c;

这在 JDK-8u45 中编译得很好,但是如果我们检查 specification for capture conversion,看起来(对我来说)这个声明 应该 导致编译时错误。

特别是,新类型变量捕获的上限 T#1glb(Bi, Ui[A1:=S1,...,An:=Sn]) 给出,在这种情况下 Bi 解析为通配符边界 C2<String> Ui[A1:=S1,...,An:=Sn] 解析为 C1<T#1>.

由此,glb(C2<?>, C1<T#1>)解析为交集类型C2<String> & C1<T#1>,这是无效的,因为C2<String>C1<T#1>都是class类型,不是接口类型,但它们都不是另一个的子类型。

这种(明显的)违反规则的行为可能在 definition of the intersection type 本身中更加明显。

我确定这不是一个错误,我只是在某个地方犯了一些简单的错误...如果它是一个错误,我希望它可以被认为是一个错误在 JLS 而不是 JDK 中,这样我可以期望能够安全地模拟行为...

感谢您的帮助!

编辑: 在昨天与 Radiodef 交谈后,我说服自己这个问题(或者至少是一种看待它的方式)是 C2<String> 可以有效地被认为是 作为 C1<T#1> 的子类型,因为 T#1 只能 everC2<String> 满足,因此可以是被认为等于它,但是包含和子类型规则不理解这种关系,因此 JLS 将无法识别子类型并且应该失败...

不过,如果您采用 C1<? extends C2<?>> d; 稍微复杂一点的情况,那就更棘手了。问题类似,但是形成捕获上限的交集类型为C2<?> & C1<T#2>,似乎无法通过与上述相同的推理得出解决方案。

Maurizio's response on compiler-dev 回答得最好。

(TL;DR javac 确实与此处的规范不一致,最佳解决方案可能介于两种方法之间)

相关错误 can be found here

非常感谢所有为这个答案做出贡献的人。