Swe*_*per 11 java language-lawyer
此代码无法编译:
List<? extends List<Number>> list = new ArrayList<>();
List<List<Double>> anotherList = (List<List<Double>>) list;
Run Code Online (Sandbox Code Playgroud)
请注意,IntelliJ 不会报告任何错误。当我单击“运行”时,它只会编译失败。
我理解为什么这不能在概念层面上编译。list是“扩展的List<Number>东西”的列表,而“东西”永远不会是List<Double>,因为List<Double>它不是 的子类型List<Number>,并且因为它们具有相同的擦除,所以没有类型可以实现两者。
但是,当我尝试按照语言规范中的措辞来确定此强制转换是否有效时,我发现语言规范似乎说这是一个有效的强制转换!
这是我的推理:
强制转换满足从S( List<? extends List<Number>>) 到T( List<List<Double>>)的窄引用转换的所有三个要求。
5.1.6.1 . 允许的缩小参考转换
如果以下所有条件都为真,则存在从引用类型 S 到引用类型 T 的收缩引用转换:
S 不是 T 的亚型
如果存在作为 T 超类型的参数化类型 X 和作为 S 超类型的参数化类型 Y,使得 X 和 Y 的擦除相同,则 X 和 Y 不可证明不同(第 4.5 节) .
以下情况之一适用:
- S 和 T 是接口类型。
- [...]
第一点和第三点是微不足道的。为了证明第二点是正确的,我们取Collection<List<Double>>为 的参数化超类型List<List<Double>>,以及Collection<? extends List<Number>>的参数化超类型List<? extends List<Number>>。它们都擦除为相同的类型Collection。现在我们需要证明Collection<? extends List<Number>>和Collection<List<Double>>不可证明是不同的(第 4.5 节)。同样的论点也适用于Iterable<...>.
编辑:我刚刚意识到 的超类型List<List<Double>>还包括诸如 的东西List<? extends List<Double>>,而不仅仅是List. 但我不认为这会否定这一说法,因为点是1出来X,并Y至少有一个通配符2的通配符范围/类型参数X和Y彼此的亚型。
如果以下任一条件为真,则两个参数化类型可证明是不同的:
它们是不同泛型类型声明的参数化。
它们的任何类型参数都可以证明是不同的。
显然,由于它们都擦除为相同的类型,因此第一个条件不可能为真。我们只需要证明第二个条件为假。
在§4.5.1 中,规范定义了“类型参数可以证明是不同的”:
如果以下条件之一为真,则两个类型参数可证明是不同的:
- [...]
- 一种类型参数是类型变量或通配符,其上限(来自捕获转换(第 5.1.10 节),如有必要)为 S;另一个类型参数 T 不是类型变量或通配符;也没有|S| <: |T| 也不|T| <: |S| (第 4.8 节、第 4.10 节)。
(为简洁起见,没有显示其他(微不足道的错误)条件)这里,SisList<Number>和Tis List<Double>。两者 |S| <: |T| 和|T| <: |S| 成立,如 |S| 和|T| 是相同的类型。是的,子类型关系是自反的,因为超类型关系是自反的(它被定义为直接超类型关系上的自反和传递闭包)。
因此类型参数Collection<? extends List<Number>>和Collection<List<Double>>不可证明不同,因此List<? extends List<Number>>并List<List<Double>>没有可证明不同,所以有(或应是)转换从List<? extends List<Number>>到List<List<Double>>!
我的推理错误在哪里?我错过了规范的其他部分吗?
好吧,我会在Holger 确认并回答后说:JLS 在这个位置(至少)未指定。有一些相关的 JDK bug 也围绕着同样的想法,值得注意的是这个,它通过以下方式直接解决了你的问题:
\n\n\n....否则,将通配符和类型变量映射到它们的上限,然后测试它们的擦除是否是相关的类或接口(即,一个擦除的类型是另一种的子类型)
\n
只是为了立即开始下一句话:
\n\n\n这是不健全的...
\n
因此,该错误承认 JLS 需要围绕本章进行一些更正。
\n从您对 JLS 的引用中,我也一直在努力解决两点:
\n一个类型参数是类型变量或通配符,具有上限(如有必要,来自捕获转换 (\xc2\xa75.1.10) ...
\n我确实知道什么是捕获转换,但我不知道它可能是可选执行的(通过“如果需要”)。我一直认为它在每个地点、每时每刻都在进行。
\n捕获的转换类型的上限是多少?
\n例如,就您而言,是上限 List<Number>还是?List<?>根据我的理解(或者缺乏精确的 JLS 解释),这可以用任何一种方式来理解。
所有这些(+你对 JLS 的巨大刮擦)让我怀疑这里 JLS 的正确性,特别是因为它javac不遵循这些完全相同的规则。
| 归档时间: |
|
| 查看次数: |
170 次 |
| 最近记录: |