ChatGPT解决这个技术问题 Extra ChatGPT

Implementing two interfaces in a class with same method. Which interface method is overridden?

Two interfaces with same method names and signatures. But implemented by a single class then how the compiler will identify the which method is for which interface?

Ex:

interface A{
  int f();
}

interface B{
  int f();
}

class Test implements A, B{   
  public static void main(String... args) throws Exception{   

  }

  @Override
  public int f() {  // from which interface A or B
    return 0;
  }
}   

p
polygenelubricants

If a type implements two interfaces, and each interface define a method that has identical signature, then in effect there is only one method, and they are not distinguishable. If, say, the two methods have conflicting return types, then it will be a compilation error. This is the general rule of inheritance, method overriding, hiding, and declarations, and applies also to possible conflicts not only between 2 inherited interface methods, but also an interface and a super class method, or even just conflicts due to type erasure of generics.

Compatibility example

Here's an example where you have an interface Gift, which has a present() method (as in, presenting gifts), and also an interface Guest, which also has a present() method (as in, the guest is present and not absent).

Presentable johnny is both a Gift and a Guest.

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { void present(); }

    interface Presentable extends Gift, Guest { }

    public static void main(String[] args) {
        Presentable johnny = new Presentable() {
            @Override public void present() {
                System.out.println("Heeeereee's Johnny!!!");
            }
        };
        johnny.present();                     // "Heeeereee's Johnny!!!"

        ((Gift) johnny).present();            // "Heeeereee's Johnny!!!"
        ((Guest) johnny).present();           // "Heeeereee's Johnny!!!"

        Gift johnnyAsGift = (Gift) johnny;
        johnnyAsGift.present();               // "Heeeereee's Johnny!!!"

        Guest johnnyAsGuest = (Guest) johnny;
        johnnyAsGuest.present();              // "Heeeereee's Johnny!!!"
    }
}

The above snippet compiles and runs.

Note that there is only one @Override necessary!!!. This is because Gift.present() and Guest.present() are "@Override-equivalent" (JLS 8.4.2).

Thus, johnny only has one implementation of present(), and it doesn't matter how you treat johnny, whether as a Gift or as a Guest, there is only one method to invoke.

Incompatibility example

Here's an example where the two inherited methods are NOT @Override-equivalent:

public class InterfaceTest {
    interface Gift  { void present(); }
    interface Guest { boolean present(); }

    interface Presentable extends Gift, Guest { } // DOES NOT COMPILE!!!
    // "types InterfaceTest.Guest and InterfaceTest.Gift are incompatible;
    //  both define present(), but with unrelated return types"
}

This further reiterates that inheriting members from an interface must obey the general rule of member declarations. Here we have Gift and Guest define present() with incompatible return types: one void the other boolean. For the same reason that you can't an void present() and a boolean present() in one type, this example results in a compilation error.

Summary

You can inherit methods that are @Override-equivalent, subject to the usual requirements of method overriding and hiding. Since they ARE @Override-equivalent, effectively there is only one method to implement, and thus there's nothing to distinguish/select from.

The compiler does not have to identify which method is for which interface, because once they are determined to be @Override-equivalent, they're the same method.

Resolving potential incompatibilities may be a tricky task, but that's another issue altogether.

References

JLS 8.4.2 Method Signature

JLS 8.4.8 Inheritance, Overriding, and Hiding

JLS 8.4.8.3 Requirements in Overriding and Hiding

JLS 8.4.8.4 Inheriting Methods with Override-Equivalent Signatures "It is possible for a class to inherit multiple methods with override-equivalent signatures."

"It is possible for a class to inherit multiple methods with override-equivalent signatures."


Thanks - this was helpful. However, I had a further question on incompatibility, which I've posted as a new question
BTW This changes a little with the support of default methods in Java 8.
Composite classes to resolve potential incompatibilities may be the trick :), but, I never had such problem, and still it is evident it may happen.
This article presents a design pattern that can be used to somewhat deal with the situation where you need to implement two Colliding Interface, say Foo and Bar. Basically you have your class implement one of the interfaces, say Foo, and provide a Bar asBar() method to return an inner class that implements the second Bar interface. Not perfect since your class is ultimately not "a Bar", but it could be useful in some circumstances.
im a java developer but c# is really more clever on this : stackoverflow.com/questions/2371178/…
C
Community

This was marked as a duplicate to this question https://stackoverflow.com/questions/24401064/understanding-and-solving-the-diamond-problems-in-java

You need Java 8 to get a multiple inheritance problem, but it is still not a diamon problem as such.

interface A {
    default void hi() { System.out.println("A"); }
}

interface B {
    default void hi() { System.out.println("B"); }
}

class AB implements A, B { // won't compile
}

new AB().hi(); // won't compile.

As JB Nizet comments you can fix this my overriding.

class AB implements A, B {
    public void hi() { A.super.hi(); }
}

However, you don't have a problem with

interface D extends A { }

interface E extends A { }

interface F extends A {
    default void hi() { System.out.println("F"); }
}

class DE implement D, E { }

new DE().hi(); // prints A

class DEF implement D, E, F { }

new DEF().hi(); // prints F as it is closer in the heirarchy than A.

wow. this is new to me. Why did they have to create default in java 8 ?
To facilitate adding new methods to interfaces (specifically collections interfaces) without breaking 60% of the codebase.
@BoratSagdiyev The biggest reason was to support closues and make the more useful. See Collection.stream(). Have a look at List.sort() docs.oracle.com/javase/8/docs/api/java/util/… They have added a method for all Lists, without having to change any specific implementation. They added Collection.removeIf() which is useful
@TassosBassoukos +1 say you have your own implementation of List, now you can myList.stream() it or myList.sort() it without changing your code
@PeterLawrey: AB won't compile because it has to override hi() (to fix the ambiguity). For example, by implementing it as A.super.hi() to choose to implement it the same way as A.
A
Ash

As far as the compiler is concerned, those two methods are identical. There will be one implementation of both.

This isn't a problem if the two methods are effectively identical, in that they should have the same implementation. If they are contractually different (as per the documentation for each interface), you'll be in trouble.


It explains why Java does not allow you extends more than one class
@ArthurRonald, actually it just looks related. However, IMO, class which extends more than one class can run into Diamond Problem (which is duplicated object state in the most-derived class) and that's most likely why Java took its users away from the troubles. On the other hand, class which implements more than one class can never run into Diamond Problem simply because interface do not provide state to objects. And the problem is purely due to syntax limitations - inability to fully qualify function call.
M
Michael Borgwardt

There is nothing to identify. Interfaces only proscribe a method name and signature. If both interfaces have a method of exactly the same name and signature, the implementing class can implement both interface methods with a single concrete method.

However, if the semantic contracts of the two interface method are contradicting, you've pretty much lost; you cannot implement both interfaces in a single class then.


P
Paul Whelan

Well if they are both the same it doesn't matter. It implements both of them with a single concrete method per interface method.


C
Constantin

As in interface,we are just declaring methods,concrete class which implements these both interfaces understands is that there is only one method(as you described both have same name in return type). so there should not be an issue with it.You will be able to define that method in concrete class.

But when two interface have a method with the same name but different return type and you implement two methods in concrete class:

Please look at below code:

public interface InterfaceA {
  public void print();
}


public interface InterfaceB {
  public int print();
}

public class ClassAB implements InterfaceA, InterfaceB {
  public void print()
  {
    System.out.println("Inside InterfaceA");
  }
  public int print()
  {
    System.out.println("Inside InterfaceB");
    return 5;
  }
}

when compiler gets method "public void print()" it first looks in InterfaceA and it gets it.But still it gives compile time error that return type is not compatible with method of InterfaceB.

So it goes haywire for compiler.

In this way, you will not be able to implement two interface having a method of same name but different return type.


d
dcanh121

Try implementing the interface as anonymous.

public class MyClass extends MySuperClass implements MyInterface{

MyInterface myInterface = new MyInterface(){

/* Overrided method from interface */
@override
public void method1(){

}

};

/* Overrided method from superclass*/
@override
public void method1(){

}

}

P
Payel Senapati

The following two approaches can also be taken to implement both the duplicate methods and avoid ambiguity -

APPROACH 1:

App.java -

public class App {
    public static void main(String[] args) {
        TestInterface1 testInterface1 = new TestInterface1();
        TestInterface2 testInterface2 = new TestInterface2();
        testInterface1.draw();
        testInterface2.draw();
    }
}

TestInterface1.java -

public class TestInterface1 implements Circle {
    
}

TestInterface2.java -

public class TestInterface2 implements Rectangle {
    
}

Circle.java -

public interface Circle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing circle");
    }
}

Rectangle.java -

public interface Rectangle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing rectangle");
    }
}

Drawable.java -

public interface Drawable {
    default void draw() {
        System.out.println("Drawing");
    }
}

Output -

Drawing circle
Drawing rectangle

APPROACH 2:

App.java -

public class App {
    public static void main(String[] args) {
        
        Circle circle = new Circle() {
                
        };
        Rectangle rectangle = new Rectangle() {
                
        };

        circle.draw();
        rectangle.draw();
    }
}

Circle.java -

public interface Circle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing circle");
    }
}

Rectangle.java -

public interface Rectangle extends Drawable {
    @Override
    default void draw() {
        System.out.println("Drawing rectangle");
    }
}

Drawable.java -

public interface Drawable {
    default void draw() {
        System.out.println("Drawing");
    }
}

Output -

Drawing circle
Drawing rectangle

关注公众号,不定期副业成功案例分享
Follow WeChat

Success story sharing

Want to stay one step ahead of the latest teleworks?

Subscribe Now