JLS 的哪一部分指定不能从 List< 进行转换?将 List> 扩展到 List>?

2024-06-10

(这个问题的灵感来自这个问题 https://stackoverflow.com/q/66037939/5133585,我错误地回答了。)

此代码无法编译:

List<? extends List<Number>> list = new ArrayList<>();
List<List<Double>> anotherList = (List<List<Double>>) list;

请注意,IntelliJ 不会报告任何错误。仅当我单击“运行”时,它才无法编译。

我明白为什么这不能在概念层面上编译。list是一个“延伸的东西”的列表List<Number>”,而“某物”永远不可能List<Double>, 因为List<Double>不是 的子类型List<Number>,并且因为没有类型可以实现两者,因为它们具有相同的擦除。

然而,当我尝试按照语言规范中的措辞来确定这个强制转换是否有效时,我发现语言规范似乎说这是一个有效的强制转换!

这是我的推理:

演员阵容满足从缩小参考转换的所有三个要求S (List<? extends List<Number>>) to T (List<List<Double>>).

5.1.6.1 https://docs.oracle.com/javase/specs/jls/se14/html/jls-5.html#jls-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>>, and Collection<? extends List<Number>>成为参数化的超类型List<? extends List<Number>>。他们都擦除为相同的类型Collection。现在我们需要证明Collection<? extends List<Number>> and Collection<List<Double>>不是可证明不同(§4.5) https://docs.oracle.com/javase/specs/jls/se14/html/jls-4.html#jls-4.5。同样的论点也适用于Iterable<...>.

Edit: I just realised that the supertypes of List<List<Double>> also include things like List<? extends List<Double>>, not just the superinterfaces of List. But I don't think that will invalidate this argument, as the point is that 1. out of X and Y there is at least one wildcard 2. the wildcard bounds/type arguments of X and Y are subtypes of each other.

两个参数化类型可以证明是不同的,如果 以下是正确的:

  • 它们是不同泛型类型声明的参数化。

  • 它们的任何类型参数都可以证明是不同的。

显然,由于它们都擦除为相同类型,因此第一个条件不可能为真。我们只需要证明第二个条件是错误的。

In §4.5.1 https://docs.oracle.com/javase/specs/jls/se14/html/jls-4.html#jls-4.5.1,规范定义了“类型参数可证明是不同的”:

如果满足以下条件之一,则两个类型参数可证明是不同的 真的:

  • [...]
  • 一个类型参数是类型变量或通配符,上限为 S(来自捕获转换(第 5.1.10 节),如有必要);和 其他类型参数 T 不是类型变量或通配符;也没有 |S|

(为了简洁起见,没有显示其他(完全错误的)条件)这里,S is List<Number> and T is List<Double>。两者|S| direct超类型关系)。

因此,类型参数Collection<? extends List<Number>> and Collection<List<Double>>无法证明是不同的,所以List<? extends List<Number>> and List<List<Double>>无法证明不同,因此存在(或应该) 的转换List<? extends List<Number>> to List<List<Double>>!

我的推理错误在哪里?我错过了规范的其他部分吗?


嗯,我稍后再说霍尔格的确认与答复 https://stackoverflow.com/a/48347198/2711488:JLS 在此位置未指定(至少)。有一些相关的 JDK bug 围绕着相同的想法,值得注意this one https://bugs.openjdk.java.net/browse/JDK-8078084,这直接回答了你的问题:

....否则,将通配符和类型变量映射到它们的上限,然后测试它们的擦除是否是相关的类或接口(即,一个擦除类型是另一种类型的子类型)

只是为了立即开始下一句话:

这是不健全的...

因此,该错误承认 JLS 需要围绕本章进行一些更正。

从您对 JLS 的引用中,我也一直在努力解决两点:

  • 一个类型参数是类型变量或通配符,具有上限(如有必要,来自捕获转换 (§5.1.10))...

    我知道什么捕获转换是,但我不知道它可能是可选执行的(通过“如果需要”)。我一直认为它在每个地点、每时每刻都在进行。

  • 什么是上限 from a 捕获的转换类型?

    在你的情况下,是这样的上限 List<Number> or List<?>, 例如?根据我的理解(或者缺乏精确的 JLS 解释),这可以用任何一种方式来理解。

所有这些(+你对 JLS 的巨大刮擦)让我怀疑这里 JLS 的正确性,特别是因为javac不遵循这些完全相同的规则。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

JLS 的哪一部分指定不能从 List< 进行转换?将 List> 扩展到 List>? 的相关文章

随机推荐

  • SQL 注入:replace("'", "''") 还不够好吗?

    虽然我当然可以看到使用参数进行 SQL 查询的优点 特别是在处理日期时间和类似的事情时 但我仍然不确定参数作为only防止SQL注入的方法 事实是 我继承了一个应用程序 它有类似的东西 SELECT Field FROM Table WHE
  • JBoss Weld + java.lang.OutOfMemoryError:永久代空间

    我刚刚切换到 Weld 以利用 CDI JSF 2 Beans 对话范围 这是我的 Maven 依赖项
  • 获取 TransactSql 批处理中的语句数计数

    对于不使用 Delphi 的读者 虽然以下内容是根据 Delphi 编码来表达的 但我的实际技术问题不是特定于 Delphi 的 而是关于如何找出 Sql Server 如何 理解 TransactSql 批处理提交给它 TAdoQuery
  • 写入 Delta 表时检测到架构不匹配 - Azure Databricks

    我尝试将 small radio json json 加载到 Delta Lake 表 在此代码之后我将创建表 我尝试创建 Delta 表 但收到错误 写入 Delta 表时检测到架构不匹配 可能与分区有关events write form
  • 向前声明类模板显式/部分专业化有什么意义?

    C 98 标准规定 temp class spec 部分专业化声明本身不能通过名称查找找到 如果显式专业化也是如此 则这会使类模板显式 部分专业化的前向声明不可见 temp class spec match 当在需要实例化该类的上下文中使用
  • 如何获取 PR 标题并将其存储在变量中

    我希望能够获取 PR 消息并将其存储为 Azure Devops 中的变量 以便我可以将标题更改为 SKIP TEST 并在管道中扫描它 而不是手动浏览变量 UI 我想我只需要执行某种 REST API 调用 因为我已经有了 PR ID 和
  • 在 Symfony 2 项目中安装 Bootstrap 主题

    我正在考虑安装这个主题 http bootswatch com superhero 在我的SF2项目中 我注意到页面顶部有4个文件可供下载 即 bootstrap min css 引导程序 css 无变量 bootswatch less 我
  • flutter SDK是否提供了为Windows Phone开发应用程序的框架?

    我想知道google是否计划支持除iOS和Android以外的任何其他平台使用Flutter进行跨平台开发 像React Native Windows for React Native一样 Flutter是否有支持Windows Phone
  • Android 中的错误消息“HTTP 413 请求实体太大”

    当我使用 POST 方法使用 Multipart Part 发送图像文件时 它抛出此错误 retrofit2 adapter rxjava HttpException HTTP 413 请求实体太大 通过该错误 很明显您在请求中发送的文件大
  • 如何在 JPA 2 / Hibernate 中进行可移植和本机 ID 生成?

    我希望在当前运行 Hibernate 和 MySQL 的 JPA 2 实体上生成本机和可移植的 ID 当使用 GenerateValue strategy AUTO 时 hibernate 默认为 MySQL 上的 hibernate se
  • 用户反馈收集API服务

    标记为 android 以便有人真正阅读本文 但同样适用于其他应用程序平台 我们有许多 Android 和 iPhone 应用程序 它们的用户界面中融入了用户反馈功能 这些允许用户留下评论 报告错误 对应用程序进行评分 请求支持等 目前 应
  • 如何从销售订单打印 POS 收据?

    我需要打印具有相同产品数量等的销售订单的 POS 收据 在销售订单中 我创建了一个按钮 打印 POS 收据 使用此按钮 我想触发一个方法 打印出带有销售订单行的收据 因此 我需要找到创建 POS 收据并将销售订单行值传递给它的方法 那么 P
  • 使用 win32com 访问 Excel 文件的问题

    每个人 我一直在 Python 中使用 win32com client 模块来访问包含 VBA 宏的 Excel 文件的单元格 代码中的一个声明 xl win32com client gencache EnsureDispatch Exce
  • 处理两个传入的数据流并将它们组合在 python 中?

    我一直在研究Python中线程 多处理异步等的各种选项 作为处理两个传入流并将它们组合起来的方法 有关的信息很多 但示例往往令人费解且复杂 更常见的是将单个任务拆分为多个线程或进程 以加快任务的最终结果 我有一个通过套接字传入的数据流 当前
  • Identity Server 4 无提示续订错误响应:login_required

    我已经从以下位置克隆了存储库redux oidc 示例 https github com maxmantz redux oidc example它在大多数情况下都有效 但几个小时后它会出现以下错误 操作负载 ErrorResponse lo
  • Mongodb简单前缀查询与正则表达式和排序很慢

    我被这个简单的前缀查询困住了 虽然蒙戈文档 http www mongodb org display DOCS Advanced Queries AdvancedQueries RegularExpressions声明您可以通过使用前缀正则
  • PictureBox PaintEvent与其他方法

    我的表单中只有一个图片框 我想用该图片框上的一种方法绘制圆圈 但我不能这样做并且不起作用 方法是 private Bitmap Circle Bitmap bmp Graphics gfx SolidBrush firca dis new
  • Symfony 2 SecurityContext 类已弃用

    当我尝试访问 symfony demo 上的 app example 时 出现以下错误 错误 Symfony Component Security Core SecurityContext 类是 自 2 6 版本起已弃用 并将在 3 0 中
  • android - 如何在android中打开kml文件

    我的 SD卡中存储了一个 KML 文件 我想通过我的应用程序中的谷歌地图打开它 所以我使用了下面的代码 但我收到错误消息 android非法状态异常无法执行活动的方法 我不想绘制地图 只是想打开一个已经存储在我的SD卡中的kml文件并显示它
  • JLS 的哪一部分指定不能从 List< 进行转换?将 List> 扩展到 List>?

    这个问题的灵感来自这个问题 https stackoverflow com q 66037939 5133585 我错误地回答了 此代码无法编译 List