Java - Method name collision in interface implementation

40,889

Solution 1

No, there is no way to implement the same method in two different ways in one class in Java.

That can lead to many confusing situations, which is why Java has disallowed it.

interface ISomething {
    void doSomething();
}

interface ISomething2 {
    void doSomething();
}

class Impl implements ISomething, ISomething2 {
   void doSomething() {} // There can only be one implementation of this method.
}

What you can do is compose a class out of two classes that each implement a different interface. Then that one class will have the behavior of both interfaces.

class CompositeClass {
    ISomething class1;
    ISomething2 class2;
    void doSomething1(){class1.doSomething();}
    void doSomething2(){class2.doSomething();}
}

Solution 2

There's no real way to solve this in Java. You could use inner classes as a workaround:

interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
    private int value;
    public void m() { ++value; } // Alfa.m()
    public Beta asBeta() {
        return new Beta(){
            public void m() { --value; } // Beta.m()
        };
    }
}

Although it doesn't allow for casts from AlfaBeta to Beta, downcasts are generally evil, and if it can be expected that an Alfa instance often has a Beta aspect, too, and for some reason (usually optimization is the only valid reason) you want to be able to convert it to Beta, you could make a sub-interface of Alfa with Beta asBeta() in it.

Solution 3

If you are encountering this problem, it is most likely because you are using inheritance where you should be using delegation. If you need to provide two different, albeit similar, interfaces for the same underlying model of data, then you should use a view to cheaply provide access to the data using some other interface.

To give a concrete example for the latter case, suppose you want to implement both Collection and MyCollection (which does not inherit from Collection and has an incompatible interface). You could provide a Collection getCollectionView() and MyCollection getMyCollectionView() functions which provide a light-weight implementation of Collection and MyCollection, using the same underlying data.

For the former case... suppose you really want an array of integers and an array of strings. Instead of inheriting from both List<Integer> and List<String>, you should have one member of type List<Integer> and another member of type List<String>, and refer to those members, rather than try to inherit from both. Even if you only needed a list of integers, it is better to use composition/delegation over inheritance in this case.

Solution 4

The "classical" Java problem also affects my Android development...
The reason seems to be simple:
More frameworks/libraries you have to use, more easily things can be out of control...

In my case, I have a BootStrapperApp class inherited from android.app.Application,
whereas the same class should also implement a Platform interface of a MVVM framework in order to get integrated.
Method collision occurred on a getString() method, which is announced by both interfaces and should have differenet implementation in different contexts.
The workaround (ugly..IMO) is using an inner class to implement all Platform methods, just because of one minor method signature conflict...in some case, such borrowed method is even not used at all (but affected major design semantics).
I tend to agree C#-style explicit context/namespace indication is helpful.

Solution 5

The only solution that came in my mind is using referece objects to the one you want to implent muliple interfaceces.

eg: supposing you have 2 interfaces to implement

public interface Framework1Interface {

    void method(Object o);
}

and

public interface Framework2Interface {
    void method(Object o);
}

you can enclose them in to two Facador objects:

public class Facador1 implements Framework1Interface {

    private final ObjectToUse reference;

    public static Framework1Interface Create(ObjectToUse ref) {
        return new Facador1(ref);
    }

    private Facador1(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework1Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork1(o);
    }
}

and

public class Facador2 implements Framework2Interface {

    private final ObjectToUse reference;

    public static Framework2Interface Create(ObjectToUse ref) {
        return new Facador2(ref);
    }

    private Facador2(ObjectToUse refObject) {
        this.reference = refObject;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof Framework2Interface) {
            return this == obj;
        } else if (obj instanceof ObjectToUse) {
            return reference == obj;
        }
        return super.equals(obj);
    }

    @Override
    public void method(Object o) {
        reference.methodForFrameWork2(o);
    }
}

In the end the class you wanted should something like

public class ObjectToUse {

    private Framework1Interface facFramework1Interface;
    private Framework2Interface facFramework2Interface;

    public ObjectToUse() {
    }

    public Framework1Interface getAsFramework1Interface() {
        if (facFramework1Interface == null) {
            facFramework1Interface = Facador1.Create(this);
        }
        return facFramework1Interface;
    }

    public Framework2Interface getAsFramework2Interface() {
        if (facFramework2Interface == null) {
            facFramework2Interface = Facador2.Create(this);
        }
        return facFramework2Interface;
    }

    public void methodForFrameWork1(Object o) {
    }

    public void methodForFrameWork2(Object o) {
    }
}

you can now use the getAs* methods to "expose" your class

Share:
40,889
Bhaskar
Author by

Bhaskar

Java Programmer

Updated on July 08, 2022

Comments

  • Bhaskar
    Bhaskar almost 2 years

    If I have two interfaces , both quite different in their purposes , but with same method signature , how do I make a class implement both without being forced to write a single method that serves for the both the interfaces and writing some convoluted logic in the method implementation that checks for which type of object the call is being made and invoke proper code ?

    In C# , this is overcome by what is called as explicit interface implementation. Is there any equivalent way in Java ?

  • Bhaskar
    Bhaskar about 14 years
    But this way , I cannot pass an instance of CompositeClass somewhere a reference of the interfaces ( ISomething or ISomething2 ) are expected ? I cannot even expect client code to be able to cast my instance to the appropriate interface , so am I not loosing something by this restriction ? Also note that in this way , when writing classes that actually implement the respective interfaces , we loose the benefit of having the code into a single class , which may be a serious impediment sometimes.
  • jjnguy
    jjnguy about 14 years
    @Bhaskar, you make valid points. The best advice I have is add a ISomething1 CompositeClass.asInterface1(); and ISomething2 CompositeClass.asInterface2(); method to that class. Then you can just get one or the other out of the composite class. There is no great solution to this problem though.
  • Bhaskar
    Bhaskar about 14 years
    Speaking of the confusing situations this can lead to , can you give an example ? Can we not think of the interface name added to the method name as an extra scope resolution which can then avoid the collision/ confusion ?
  • Zaid Masud
    Zaid Masud over 11 years
    Do you mean anonymous class rather than inner class?
  • gustafc
    gustafc over 11 years
    @ZaidMasud I mean inner classes, since they can access the private state of the enclosing object). These inner classes can of course be anonymous, too.
  • Anirudhan J
    Anirudhan J over 10 years
    @Bhaskar Its better if our classes adhere to single responsibility principle. If there exists a class that implements two very different interfaces i think the design should be reworked to split the classes to take care of single responsibility.
  • supercat
    supercat over 10 years
    How confusing would it be, really, to allow something like public long getCountAsLong() implements interface2.getCount {...} [in case the interface requires a long but users of the class expect int] or private void AddStub(T newObj) implements coolectionInterface.Add [assuming collectionInterface has a canAdd() method, and for all instances of this class it returns false]?
  • Drew Noakes
    Drew Noakes over 9 years
    "That can lead to many confusing situations" -- please elaborate. I've never found this to be a problem in C# and really miss it occasionally in Java. Ultimately it's straightforward to reason about which interface implementation will be called when the implementation is explicit.
  • nightpool
    nightpool about 8 years
    I don't think so. You're forgetting libraries that require you to implement different interfaces to be compatible with them. You can run into this by using multiple conflicting libraries a lot more often then you run into this in your own code.
  • Michael Aaron Safyan
    Michael Aaron Safyan about 8 years
    @nightpool if you use multiple libraries that each require different interfaces, it is still not necessary for a single object to implement both interfaces; you can have the object have accessors for returning each of the two different interfaces (and call the appropriate accessor when passing along the object to one of the underlying libraries).
  • Damn Vegetables
    Damn Vegetables almost 8 years
    I never realised how C# was thoughtful and feature-rich until I started using Java for Android development. I took those C# features for granted. Java lacks too many features.
  • Dude156
    Dude156 over 3 years
    What occurs if we have two methods in the interfaces with different return types? So a String doSomething(); in one interface and a double doSomething(); in another interface. Which guy gets implemented?
  • Holger
    Holger over 2 years
    @supercat very confusing, obviously. I can’t even read that comment…