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

2022-09-03 08:14:24

给定以下两个类定义:

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

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

请考虑以下类型声明:

C1<? extends C2<String>> c;

这在 JDK-8u45 中编译得很好,但是如果我们检查捕获转换的规范,似乎(在我看来)此声明应该会导致编译时错误。

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

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

这种(明显的)规则违规可能在交叉点类型本身的定义中更加清晰。

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

感谢您的任何帮助!

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

但是,如果您采用 稍微复杂一些的情况,则更棘手。问题是相似的,但是在捕获上形成上限的交集类型显示为 ,其中似乎没有解决方案可以通过与上述相同的推理得出。C1<? extends C2<?>> d;C2<?> & C1<T#2>


答案 1

Maurizio在编译器开发上的回应最好地回答了这个问题。

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

可以在此处找到相关的错误。

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


答案 2

推荐