处理同音继承方法的规则是什么? [英] What are the rules to handle homonym inherited methods?

查看:27
本文介绍了处理同音继承方法的规则是什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图了解 Java 如何处理当具体类从不同类/接口继承(抽象或具体)具有相同名称的方法时出现的歧义情况.

I'm trying to understand how Java handles cases of ambiguity that come out when a concrete class inherits (abstract or concrete) methods having the same name from different classes/interfaces.

我一直无法找到一般规则,这就是为什么我决定花一些时间通过使用实际方法来解决这个问题.

I've not been able to find a general rule, this is why I decided, once for all, to spend some time on this by using a practical approach.

我考虑了 8 种不同的情况,结合起来

I considered 8 different cases, combining

  • 抽象方法
  • 非抽象方法
  • 抽象类
  • 界面

导致这个方案:

                           +-------------------------+
                           |       INTERFACE         |
                           +----------+--------------|
                           | abstract | non-abstract |
                           | method   | method       |
+-----------+--------------+----------+--------------+
|           | abstract     |          |              |
| ABSTRACT  | method       |    1a    |      2a      |
|           +--------------+----------+--------------+
|   CLASS   | non-abstract |          |              |
|           | method       |    3a    |      4a      |
+-----------+--------------+----------+--------------+
|           | abstract     |          |              |
|           | method       |    1b    |      2b      |
| INTERFACE +--------------+----------+--------------+
|           | non-abstract |          |              |
|           | method       |    3b    |      4b      |
+-----------+--------------+----------+--------------+

这里每个案例都被实施和评论:

And here every case is implemented and commented:

// (1a) 
// A - abstract method  
// I - abstract method
//
// Implementation needed to avoid compilation error:
//  "The type B1 must implement the inherited abstract method A1.foo()"
//
abstract class A1{                  abstract void foo();    }
interface I1{                       void foo();             }
class B1 extends A1 implements I1{  public void foo(){}     }

// (2a)
// A - abstract method
// I - non-abstract method  
//
// Implementation needed to avoid compilation error:
//  "The type B2 must implement the inherited abstract method A2.foo()"
//
abstract class A2{                  abstract void foo();    }
interface I2{                       default void foo(){}    }
class B2 extends A2 implements I2{  public void foo(){}     }

// (3a) 
// A - non-abstract method  
// I - abstract method
//
// Implementation not needed
//
abstract class A3{                  public void foo(){}     }
interface I3{                       void foo();             }
class B3 extends A3 implements I3{                          }

// (4a)
// A - non-abstract method
// I - non-abstract method  
//
// Implementation not needed
//
abstract class A4              {    public void foo(){System.out.println("A4");}}
interface I4{default void foo(){    System.out.println("I4");}                  }
class B4 extends A4 implements I4{  B4(){foo();} /*prints "A4"*/                }



// (1b) 
// J - abstract method  
// K - abstract method
//
// Implementation needed to avoid compilation error:
//  "The type C1 must implement the inherited abstract method K1.foo()"
//
interface J1{               void foo();         }
interface K1{               void foo();         }
class C1 implements J1,K1{  public void foo(){} }

// (2b)
// J - abstract method
// K - non-abstract method  
//
// Implementation needed to avoid compilation error:
//  "The default method foo() inherited from K2 conflicts with another 
//   method inherited from J2"
//
interface J2{               void foo();             }
interface K2{               default void foo(){}    }
class C2 implements J2,K2{  public void foo(){}     }

// (3b) 
// J - non-abstract method  
// K - abstract method
//
// Implementation needed to avoid compilation error:
//  "The default method foo() inherited from J3 conflicts with another 
//   method inherited from K3"
//
interface J3{               default void foo(){}    }
interface K3{               void foo();             }
class C3 implements J3,K3{  public void foo(){}     }

// (4b)
// J - non-abstract method
// K - non-abstract method  
//
// Implementation needed to avoid compilation error:
//  "Duplicate default methods named foo with the parameters () and () 
//   are inherited from the types K4 and J4"
//
interface J4{               default void foo(){}    }
interface K4{               default void foo(){}    }
class C4 implements J4,K4{  public void foo(){}     }

无论如何,尽管我能够理解示例中的大多数情况,但我还无法推断出任何一般规则".

Done that, anyway, albeit I'm able to understand the majority of the cases in my example, I've not been able to infer any "general rule" yet.

例如,我不明白为什么情况 2a3a 的工作方式不同,即为什么抽象类给出的实现被接受,而抽象类给出的实现被接受界面不是.

For instance, I don't understand why cases 2a and 3a work differently, i.e. why an implementation given by the abstract class is accepted while an implementation given by the interface is not.

我的最后一个问题是:真的存在任何一般规则"吗?有没有什么方法可以预测编译器的行为而不必记住每个案例?

My final question is: does any "genaral rule" really exist? Is there any way I can predict how the compiler will behave without having to memorize every single case?

这可能是微不足道的,但我认为这对其他人放下我的考虑很有用.

It could be trivial, but I think it can be useful to someone else putting down my considerations.

我认为您可以将所有问题总结为以下简单步骤:

I think you can summarize all the question to this simple steps:

给出这样的示例代码

abstract class A{abstract void foo();}
abstract class B extends A {protected void foo(){}}
interface I{void foo();}
interface J{default void foo(){}}

class C extends B implements I,J{}

  1. 考虑你的类 C 由它的所有方法和继承的方法组成(称之为 C*)

  1. Consider your class C made up of all its methods and inherited ones (call it C*)

class C* 实现 I,J{protected void foo(){};}

针对它实现的接口验证 C*(来自接口的每个方法歧义,包括默认方法,都必须在 C 中通过提供实现来解决).

Validate C* against interfaces it implements (every method ambiguity coming from interfaces, including default methods, must be resolved in C by giving an implementation).

3a.如果 C* 给出了一个有效的实现,请在此处停止

3a. If C* gives a valid implementation stop here

(情况并非如此,因为方法的可见性无法从公共降低到受保护)

3b.否则在 C 中需要一个有效的实现

3b. Otherwise a valid implementation is needed in C

class C extends B 实现 I,J{public void foo(){}}

推荐答案

JLS 声明 (§9.4.1.3 第 7) 段:

The JLS states (§9.4.1.3 paragraph 7):

当继承了具有匹配签名的抽象方法和默认方法时,我们会产生错误.

When an abstract and a default method with matching signatures are inherited, we produce an error.

然后他们继续解释他们为什么选择这个:

They then go on to explain why they chose this:

在这种情况下,可以优先考虑其中一个——也许我们会假设默认方法也为抽象方法提供了合理的实现.但这是有风险的,因为除了巧合的名称和签名之外,我们没有理由相信默认方法的行为与抽象方法的契约一致 - 当子接口出现时,默认方法甚至可能不存在最初是开发的.在这种情况下,要求用户主动断言默认实现是合适的(通过覆盖声明)更安全.

In this case, it would be possible to give priority to one or the other - perhaps we would assume that the default method provides a reasonable implementation for the abstract method, too. But this is risky, since other than the coincidental name and signature, we have no reason to believe that the default method behaves consistently with the abstract method's contract - the default method may not have even existed when the subinterface was originally developed. It is safer in this situation to ask the user to actively assert that the default implementation is appropriate (via an overriding declaration).

这篇关于处理同音继承方法的规则是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆