23

I have a couple of interfaces:

public interface Speaker {
    void speak();
}

public inteface Walker {
    void walk();
}

I want a method that takes instances that are both a Speaker and a Walker.

Now, I could implement another interface:

public interface WalkerSpeaker extends Walker, Speaker {

}

And accept that:

void walkAndTalk(final WalkerSpeaker x) {
    x.walk();
    x.speak();
}

But this is quite cumbersome with many combinations, and every implementation must inherit from WalkerSpeaker for it to work!

Is there a better way?

sdgfsdh
  • 33,689
  • 26
  • 132
  • 245
  • 1
    This is pretty much how it is. If its becoming cumbersome you may wanna look at your design. – Mr00Anderson Jun 15 '16 at 13:40
  • 2
    @Ravindrababu your answer to that link is just as cumbersome and highly rigid that cannot be expanded or changed easily. – Mr00Anderson Jun 15 '16 at 13:43
  • fyi: It is good practice to use `implements` instead of `extends` for interfaces. – Akunosh Jun 15 '16 at 13:44
  • @Akunosh Try to replace the `extends` with `implements` and see what the compiler thinks of it. – Kayaman Jun 15 '16 at 13:46
  • 2
    @Akunosh An `interface` can only `extend` amother `interface`. Only classes and enums use `implements` when specifying interfaces – Vince Jun 15 '16 at 13:46
  • 1
    @Akunosh an interface can extend one or more interfaces. A class can implement one or more interfaces and/or extend a class. – Davide Lorenzo MARINO Jun 15 '16 at 13:59
  • The elegant solution to this "problem" is to use structural subtyping, but alas Java does not support it. – gardenhead Jun 15 '16 at 18:04
  • This question (and the accepted answer) is not meaningful in anyway. You are avoiding creating the interface for the **method**, yet **callers** have to create the interface anyway, including callers of the accepted answer's solution. The only way to not create the interface is to not call the method, then what's the point of having the method? – PoweredByRice Apr 20 '17 at 03:37
  • @Kayaman You don't seem to understand the comment. How are you calling the method without an extra 3rd interface? In case that still doesn't make sense, **what is your T** ? – PoweredByRice Apr 20 '17 at 13:07
  • @Kayaman how are you passing in a `T` that implements `Speaker` and `Walker` without creating an extra 3rd interface? – PoweredByRice Apr 20 '17 at 13:13
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142184/discussion-between-poweredbyrice-and-kayaman). – PoweredByRice Apr 20 '17 at 13:14

1 Answers1

54

You can achieve this with generics as follows

public <T extends Speaker & Walker> void walkAndTalk(T x) {
    x.walk();
    x.speak();
}

The type parameter T will be "double-bounded" to both interfaces, so in essence T will be a WalkerSpeaker except you don't have to write a separate interface for it.

Kayaman
  • 72,141
  • 5
  • 83
  • 121
  • Perfect. Is there any overhead to this v.s. using an extra interface? I imagine not due to type-erasure. – sdgfsdh Jun 15 '16 at 13:42
  • 3
    Since generics are erased at compile-time, no there isn't. Not that it matters, since performance is a larger issue than some random method call. – Kayaman Jun 15 '16 at 13:45
  • 5
    +1, Very nice idea for this solution, but I don't like the idea that an object can be viewed with two different natures in the same method. It seems that the walkAndTalk method has more than one responsibility, so breaks the principle of Single Responsibility. – Davide Lorenzo MARINO Jun 15 '16 at 13:47
  • 5
    @DavideLorenzoMARINO It's basically a Java version of a [Mixin](https://en.wikipedia.org/wiki/Mixin) especially now with default methods. But this is just an example, so it's not very useful to consider whether it breaks some principles or not. – Kayaman Jun 15 '16 at 13:54
  • 1
    @Kayaman Yes, this is going into a mixin-like implementation. – sdgfsdh Jun 15 '16 at 14:00
  • 6
    @sdgfsdh: well, due to type erasure, the erased type of the parameter will be `Speaker` and a type cast to `Walker` inserted at byte code level to invoke the `walk()` method, but it’s unlikely to ever notice a performance impact. The first thing, HotSpot does for performance critical code, is to inline the code into the caller’s context, where the actual type of `x` which implements both interfaces is known. – Holger Jun 15 '16 at 16:23
  • @Kayaman: If one is trying to have a method which, someone that can `Walk` and `Talk`, will navigate them to a particular location, is it more helpful to have a reference to someone that can walk, and a reference to someone that can talk, and hope that both references identify the same person, or is it more helpful to accept a reference to one person who should have both abilities, and figure that if it's really necessary to have different objects play the distinct roles (e.g. someone who can talk is in a wheelchair, being pushed by someone who is mute) one can make an artificial proxy object? – supercat Jun 15 '16 at 16:58
  • 1
    Note that nothing really is "erased at compile-time" in this code. A generic method like `walkAndTalk(T)` has *two* signatures in the java classfile: the conventional non-generic one (where the parameter is of type `Speaker` as @Holger mentioned), and the generic signature of "(TT;)V". The full generic information can be recovered at runtime through Reflection. – Rogério Jun 15 '16 at 19:21
  • you do have to write the interface for it when you **call the method**. – PoweredByRice Apr 20 '17 at 03:44