捕获 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#1
由 glb(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 只能 ever 被 C2<String>
满足,因此可以是被认为等于它,但是包含和子类型规则不理解这种关系,因此 JLS 将无法识别子类型并且应该失败...
不过,如果您采用 C1<? extends C2<?>> d;
稍微复杂一点的情况,那就更棘手了。问题类似,但是形成捕获上限的交集类型为C2<?> & C1<T#2>
,似乎无法通过与上述相同的推理得出解决方案。
Maurizio's response on compiler-dev 回答得最好。
(TL;DR javac 确实与此处的规范不一致,最佳解决方案可能介于两种方法之间)
相关错误 can be found here。
非常感谢所有为这个答案做出贡献的人。
给定以下两个 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#1
由 glb(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 只能 ever 被 C2<String>
满足,因此可以是被认为等于它,但是包含和子类型规则不理解这种关系,因此 JLS 将无法识别子类型并且应该失败...
不过,如果您采用 C1<? extends C2<?>> d;
稍微复杂一点的情况,那就更棘手了。问题类似,但是形成捕获上限的交集类型为C2<?> & C1<T#2>
,似乎无法通过与上述相同的推理得出解决方案。
Maurizio's response on compiler-dev 回答得最好。
(TL;DR javac 确实与此处的规范不一致,最佳解决方案可能介于两种方法之间)
相关错误 can be found here。
非常感谢所有为这个答案做出贡献的人。