4

I always thought that two interfaces with the same method cannot be inherited by one class, as stated in many so questions.

Java jre 7, jdk 1.7

But this code here is working.

Example:

Interfaces:

public interface IObject
{
    public Object create(Object object) throws ExceptionInherit;
}

public interface IGeneric<T>
{
    public T create(T t) throws ExceptionSuper;
}

Implementing class:

public class Test implements IGeneric<Object>, IObject
{
    @Override
    public Object create(final Object object) throws ExceptionInherit
    {
        return object;
    }
}

Don't those two method declarations have the same body?

Exceptions:

The exceptions are just additive to this construct making it more complex.

public class ExceptionSuper extends Exception {}
public class ExceptionInherit extends ExceptionSuper {}

It works without any thrown exceptions too.

Further: If both methods interfaces throw different inheriting exceptions i could cast UserLogic to any of the two interfaces and retrieve a different subset of the exceptions!

Why is this working?

Edit:

The generic implementation is not even necessary:

public interface IA
{
    public void print(String arg);
}

public interface IB
{
    public void print(String arg);
}

public class Test implements IA, IB
{
    @Override
    public void print(String arg);
    {
        // print arg
    }
}
djmj
  • 5,579
  • 5
  • 54
  • 92
  • The exception `Test` throws is compatible with both of the inherited signatures, this is why this compiles fine. This is always possible because your implementation can just throw nothing, so there's no reason for the compiler to complain about inheriting those interfaces. – millimoose Oct 06 '12 at 14:25
  • I also looked at how this gets compiled by the Java compiler. Apparently, at the bytecode level, both the method `User create(User)` exists, as well as a *synthetic* method `Object create(Object)` that just invokes the typesafe method. So both the generic and the "erased" version exist, the latter probably for compatibility with invoking the class over the raw `ICreateGeneric` interface. – millimoose Oct 06 '12 at 14:32
  • It is even working without the generic interface in java 7? Is this a new feature? Or missed I something? All so questions state its not possible and thats how i learned it. – djmj Oct 06 '12 at 14:36
  • `I always thought that two interfaces with the same method cannot be inherited by one class, as stated in many so questions.` WAT? 0_0 – Denis Tulskiy Oct 06 '12 at 14:44
  • I googled that topic and found a few questions that were duplicates of: http://stackoverflow.com/questions/2598009/method-name-collision-in-interface-implementation-java – djmj Oct 06 '12 at 14:47
  • @djmj: that question is about that if two interfaces have same method signatures, a class that implements them both will implement only one method. So existence of that question contradicts your first argument :) – Denis Tulskiy Oct 06 '12 at 16:06
  • @djmj The only reason for the compiler to complain in such a case would be if the interfaces had conflicting method signatures; i.e. method signatures that can't be overloads of one another. A simple example is methods that "overload" on the return type like this: http://ideone.com/jVrIe. (That said, it works in this case: http://ideone.com/25EcZ - where the interface method return types are interfaces and it's possible for a subtype that implements both to exist.) – millimoose Oct 06 '12 at 17:50

5 Answers5

3

Now i could cast UserLogic to any of the two interfaces and retrieve a different set of exceptions!

No, you can't. See "Java Puzzlers: Traps, Pitfalls, and Corner Cases" by Joshua Bloch and Neal Gafter, Puzzle 37 Exceptionally Arcane:

Each interface limits the set of checked exceptions that method can throw. The set of checked exceptions that a method can throw is the intersection of the sets of checked exceptions that it is declared to throw in all applicable types, not the union.

So in your case implementation

create(User user) throws ExceptionInherit

is correct. But

create(User user) throws ExceptionSuper

will not compile

  • Thanks, good point! But still even without exception the interface construct works. – djmj Oct 06 '12 at 14:26
2

You wouldn't receive different exceptions because ExceptionInherit extends ExceptionSuper. But consider this:

interface X {
    public void foo() throws ExceptionA;
}

interface Y {
    public void foo() throws ExceptionB;
}

class ExceptionA extends Exception {}
class ExceptionB extends Exception {}

class Z implements X, Y {
    public void foo() throws ExceptionA {

    }
}

Notice how ExceptionA and ExceptionB are not connected through inheritance. In this case, you will receive a compile-error because ExceptionA is not compatible with the throws clause in Y.

arshajii
  • 127,459
  • 24
  • 238
  • 287
1

It would work without the generic, without the exceptions too. Even back as far as Java 1.4, and probably before.

I always thought that two interfaces with the same method cannot be inherited by one class, as stated in many so questions.

This is actually not true, and I'm unsure what questions you are referring to.

There are of course reasons for not using two interfaces with the same method signature, the most important one that the implementation can only do one thing, so if both interfaces expect different result from the method, you won't be able to satisfy both interfaces, but this wont be a compile error.

There are also reasons why it would be perfectly valid to have 2 interfaces with the same methods. If 2 interfaces extend each other, a implementation could implement both interfaces just fine. Even in a simpler situation where interfaces just share names, there is no technical limitations.

A interface only request certain methods to be available, it does not demand other interfaces to be absent.

Valid code:

public interface IDo {
    public void does();
}


public interface ITwo {
    public void does();
}

public class Test implements IDo, ITwo {
public void does() {
}
}
Dorus
  • 7,276
  • 1
  • 30
  • 36
1
I always thought that two interfaces with the same method cannot 
be inherited by one class, as stated in many so questions.

If you want to be more precise you should replace "same method", with "methods with override-equivalent signatures". A signature is "method name" + "parameters list" (some rules apply to return type and throws clause as well). You need to know what override-equivalent exactly means.

It's perfectly fine if a class implements two or more interfaces with such methods provided that:

1- All of them have the same return type OR one of those methods has a return type that is a subtype of all others. That's the return type that you should use in the implementation.

For example:

interface A {
    Integer x();
}

interface B {
    Number x();
}

interface C {
    Object x();
}

class Foo implements A, B, C
{
    Integer x() { 
        //...
    }
}

and

2- the implementation must satisfy the throws clauses of all such methods that each superinterface has declared.

So the examples you gave adhere to these rules and are perfectly fine to do.

Nylon Smile
  • 8,990
  • 1
  • 25
  • 34
0

You can definitely "implement" two interfaces that have methods of the same signatures. You get into trouble trying to "extend" two classes that have identical method implementations. Multiple-interface inheritance is GOOD; multiple-implementation inheritance is TRICKY.

An "ExceptionInherit" object can be used in place of an "ExceptionSuper" object because it inherits from it. The "ExceptionInherit" object has all the information that the "ExceptionSuper" object does (plus more). This is not true the other way around. You can't use an "ExceptionSuper" object in place of "ExceptionInherit" object because the "ExceptionInherit" code expects more than your base object has (well, potentially but not in your case).

Your implementation of the "create" method fills the ICreateUser "create" signature because it throws an "ExceptionInherit" which can be thrown to catchers of both "ExceptionInherit" and "ExceptionSuper" get all the information they need (just the base class) from the object.

You couldn't change your implementation to throw an "ExceptionSuper" because catchers expecting a "ExceptionInherit" would get an object with not enough information.

ChrisCantrell
  • 3,833
  • 1
  • 22
  • 14