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;
}
}
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."
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.
hi()
(to fix the ambiguity). For example, by implementing it as A.super.hi()
to choose to implement it the same way as A.
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.
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.
Well if they are both the same it doesn't matter. It implements both of them with a single concrete method per interface method.
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.
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(){
}
}
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
Success story sharing
default
methods in Java 8.Foo
andBar
. Basically you have your class implement one of the interfaces, sayFoo
, and provide aBar asBar()
method to return an inner class that implements the secondBar
interface. Not perfect since your class is ultimately not "a Bar", but it could be useful in some circumstances.