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

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

问题描述

我正在尝试理解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


  • 抽象方法

  • 非抽象方法

  • 抽象类

  • 接口

  • abstract methods
  • non-abstract methods
  • abstract classes
  • interfaces

产生此计划:

                           +-------------------------+
                           |       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.

例如,我不明白为什么 2a 3a 的情况不同,为什么给出一个实现由接口给出的实现不接受抽象类。

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.

我的最后一个问题是:是否真的存在genaral rule?有没有什么方法可以预测编译器的行为而不必记住每一个案例?

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 *(每个方法)来自接口的歧义,包括默认方法,必须通过给出来解决实施)。

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

C类扩展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天全站免登陆