Welche Regeln gelten für homonyme geerbte Methoden?

Ich versuche zu verstehen, wie Java mit Mehrdeutigkeiten umgeht, die auftreten, wenn eine konkrete Klasse (abstrakte oder konkrete) Methoden mit demselben Namen von verschiedenen Klassen / Schnittstellen erbt.

Ich war nicht in der Lage, eine allgemeine Regel zu finden, deshalb habe ich mich ein für allemal dazu entschlossen, eine Weile damit zu verbringen, um einen praktischen Ansatz zu verfolgen.

Ich habe 8 verschiedene Fälle in Betracht gezogen und @ kombinier

abstract Methoden nicht abstrakte Methodenabstract Klassen interfaces

Ergebnis in diesem Schema:

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

Und hier wird jeder Fall implementiert und kommentiert:

// (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(){}     }

Habe ich das trotzdem getan, obwohl ich die Mehrzahl der Fälle in meinem Beispiel verstehen kann, war ich noch nicht in der Lage, eine "allgemeine Regel" abzuleiten.

Zum Beispiel verstehe ich nicht, warum Fälle 2a und 3a anders arbeiten, d. h. warum eine von der abstrakten Klasse angegebene Implementierung akzeptiert wird, während eine von der Schnittstelle angegebene Implementierung dies nicht tut.

Meine letzte Frage lautet: Gibt es wirklich eine "allgemeine Regel"? Kann ich auf irgendeine Weise vorhersagen, wie sich der Compiler verhalten wird, ohne dass ich mir jeden einzelnen Fall merken muss?

BEARBEITE

s könnte trivial sein, aber ich denke, es kann nützlich sein, wenn jemand anderes meine Überlegungen anstell

Ich denke, Sie können alle Fragen zu diesen einfachen Schritten zusammenfassen:

Gab einen Beispielcode wie diesen

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{}

Betrachten Sie Ihre Klasse C, die aus all ihren Methoden und geerbten Methoden besteht (nennen Sie sie C *).

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

Validieren Sie C * gegen von ihm implementierte Schnittstellen (jede Methodenmehrdeutigkeit, die von Schnittstellen ausgeht, einschließlich Standardmethoden, muss in C durch Angabe einer Implementierung aufgelöst werden).

3a. Wenn C * eine gültige Implementierung ergibt, stoppen Sie hier

(it's not the case because method visibility cannot be reduced from public to protected)

3b. Andernfalls wird eine gültige Implementierung in C @ benöti

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

Antworten auf die Frage(4)

Ihre Antwort auf die Frage