接收器参数覆盖的方法是否相当于没有接收器参数的相同方法声明?

时间:2018-03-28 11:56:16

标签: java override

我对接收器参数上下文中 override-equivalent JLS 8.4.2)的定义有一个相当技术性的问题。

编辑:发布此问题后,关于接收器参数的评论中存在很多混淆。许多人似乎认为在下面的代码中使用名为this的参数是非法的,因此误解了这个问题。如果您不了解此功能,请参阅https://docs.oracle.com/javase/specs/jls/se9/html/jls-8.html#jls-8.4.1。可以在这里找到一个更容易理解的解释:http://blog.joda.org/2015/12/explicit-receiver-parameters.html。这个问题非常技术性,适用于熟悉接收器参数且熟悉Java语言规范(JLS)的经验丰富的Java开发人员。

术语覆盖等效定义如下:

  

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

     
      
  • m2m1
  • 具有相同的签名   
  • m1的签名与m2签名的删除(§4.6)相同。
  •   
     

两个方法签名m1m2覆盖等效 iff m1m2m2的子签名是m1的副标记。

因此,如果我理解正确,下面这两个方法中的两个方法不是覆盖等价的,即使直觉上我也希望它们是:

class A {
    void foo(A this) { /* ... */ }
    void foo() { /* ... */ }
}

尽管如此,显然我不能在同一个类中声明这两个方法,当我尝试这样做时,编译器正确地抱怨已经定义了foo()

我的问题包括两部分:

  1. 我是否正确理解上述两种方法不是覆盖等效的?
    • 如果不是:我错过了定义的哪一部分?
    • 如果是:JLS中的哪条规则正式禁止上述两个方法定义同时出现在同一个类中,因为在这种情况下它不能成为规则"这是一个编译时错误在类中使用覆盖等效签名声明两个方法。" JLS 8.4.2

1 个答案:

答案 0 :(得分:2)

好的,我找到了答案,我就把它留在这里,希望有朝一日能帮助别人。

我的两部分问题的答案是:

  1. 不,原帖中的两种方法覆盖等效。

  2. 定义的相关部分是JLS 8.4.2的第一句话:

  3.   

    两个方法或构造函数MN如果具有相同的名称,相同的类型参数(如果有的话),则具有相同的签名({{3 }},并且,在将N的形式参数类型调整为M的类型参数后,使用相同的形式参数类型。

    我已经读过那个部分,但我认为接收器参数虽然特殊,但被认为是(一种特殊的)形式参数。因此我假设在调整形式参数类型(...)" 后,接收器参数隐含地包含在句子中#34; (...) (强调我的)。但事实并非如此。接收器参数也是形式参数;相反,接收器参数形式参数的定义是互斥的。因此,接收器参数不是上述引文中定义的方法签名的一部分。由于 override-equivalent 的定义使用了方法签名的定义,这也意味着我原始帖子中的两个方法实际上是覆盖等价的(因为它们确实如此)有相同的签名!)。

    有关章节澄清了接收器参数确实不是正式参数,稍后会在§8.4.4部分稍后介绍:

      

    receiver参数是实例方法或内部类构造函数的可选语法设备。对于实例方法,receiver参数表示调用该方法的对象。对于内部类的构造函数,receiver参数表示新构造的对象的直接封闭实例。无论哪种方式,接收器参数仅存在以允许在源代码中表示所表示的对象的类型,以便可以注释该类型。 接收器参数不是形式参数;更确切地说,它不是任何变量(JLS 8.4.2)的声明,它永远不会绑定到在方法调用表达式或限定类实例创建表达式中作为参数传递的任何值,并且它不会产生任何影响在运行时。

    (强调我的)

    接收器参数不是形式参数的声明在那一大块文本中有点丢失。