【问题标题】:Is covariant return type overriding according jls?协变返回类型是否根据 jls 覆盖?
【发布时间】:2014-05-12 20:31:28
【问题描述】:

只是说,我的问题的重点是学会理解 jls。我相信jls里的都是真的。

考虑下一个来自 jls 的 sn-p:

8.4.8.1。覆盖(通过实例方法)

在类 C 中声明的实例方法 m1 覆盖另一个实例 方法 m2,在 A 类中声明,当且仅当满足以下所有条件时:

C 是 A 的子类。

m1 的签名是 m2 签名的子签名(第 8.4.2 节)。

要么:

m2 是公共的、受保护的或声明为具有默认访问权限的同一 打包为 C,或

m1 覆盖了一个方法 m3(m3 不同于 m1,m3 不同于 m2), 这样 m3 会覆盖 m2。

此外,如果 m1 不是抽象的,则称 m1 实现了 any 并且 它覆盖的所有抽象方法的声明。

转到子签名声明:

方法 m1 的签名是 a 的签名的子签名 方法 m2,如果:

m2 与 m1 具有相同的签名,或者

m1 的签名与签名的擦除(§4.6)相同 平方米。

关于相同的签名:

两个方法具有相同的签名,如果它们具有相同的名称和 参数类型。

哪条规则允许使用协变返回类型?

【问题讨论】:

  • 如果你编辑你的问题解释你为什么认为这是一个矛盾会更好。
  • @Luiggi Mendoza R1,适应于 d2 的类型参数(第 8.4.4 节),是 R2 的子类型。 如果 R1 是 Integer,那么 R2 可能是 Integer 或数字或对象
  • 它不兼容 方法 m1 的签名是方法 m2 签名的子签名,如果: m2 与 m1 具有相同的签名,或 m1 的签名与 m2 签名的擦除(第 4.6 节)相同。
  • 没错。再说一遍,你有什么不明白的?请注意,方法签名不涉及返回类型。
  • @Luiggi Mendoza 我忘了考虑“如果两个方法具有相同的名称和参数类型,则它们具有相同的签名”的规则。谢谢

标签: java compilation overriding


【解决方案1】:

这些规则都不允许协变返回类型。方法的签名是指方法名称及其参数的类型和顺序,而不是返回类型。

From JLS, Section 8.4.8.3:

如果返回类型为 R1 的方法声明 d1 覆盖或隐藏了返回类型为 R2 的另一个方法 d2 的声明,则 d1 必须是 d2 的返回类型可替换(第 8.4.5 节),否则会出现编译时错误发生。

此规则允许协变返回类型 - 在重写方法时优化方法的返回类型。

指的是Section 8.4.5,它声明:

如果以下任何一项为真,则返回类型为 R1 的方法声明 d1 可替代返回类型为 R2 的另一个方法 d2:

  • 如果 R1 无效,则 R2 无效。

  • 如果 R1 是原始类型,则 R2 与 R1 相同。

  • 如果 R1 是引用类型,则以下情况之一为真:

    • R1,适配d2的类型参数(§8.4.4),是R2的子类型

    • 可以通过未经检查的转换(第 5.1.9 节)将 R1 转换为 R2 的子类型。

    • d1 与 d2 的签名不同(第 8.4.2 节),并且 R1 = |R2|。

(强调我的)

我加粗的那部分允许协变返回类型。

【讨论】:

  • 还有一条注释说 “此规则允许协变返回类型 - 在重写方法时改进方法的返回类型。” 关于您的第一次引用。
  • 矛盾 如果满足以下所有条件,则在类 C 中声明的实例方法 m1 会覆盖在类 A 中声明的另一个实例方法 m2:...R1,适应d2的类型参数(§8.4.4),是R2的子类型。
  • @arshajii 有趣的是,我刚刚得到了我需要的部分,却错过了那句话。我现在已经包含了它。
  • @gstackoverflow “是 R2 的子类型”子句说明了 d1 可以在没有编译器错误的情况下“返回类型可替代”的一种方式。这并不矛盾,它是定义的一部分。
  • @gstackoverflow JLS 正在做的是添加另一个需要覆盖的方法。 除了 m1 的签名是m2 的子签名之外,m2 必须是返回类型可替换的。
猜你喜欢
  • 2015-04-01
  • 2012-07-24
  • 1970-01-01
  • 2021-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多