40

Suppose I have these interfaces:

public interface I1 {
  void foo();
}

public interface I2 {
  void bar();
}

and the classes:

public class A extends AParent implements I1, I2 {
   // code for foo and bar methods here
}

public class B extends BParent implements I1, I2 {
  // code for foo and bar methods here
}

public class C extends CParent implements I1 {
  // code for foo method here
}

Now, with generics I can have a method like:

public <T extends I1 & I2> void method(T param) {
  param.foo();
  param.bar();
}

and I can call it with both A and B as parameters, but not with C (it doesn't implement I2).

Was there a way of achieving this type of type safety pre generics (java < 1.5).

Consider that A, B and C have different inheritance trees, and it's not really an option to do something like AParent and BParent having a common parent themselves.

I know you could do:

public void method(I1 param) {
  param.foo();
  ((I2)param).bar();
}

but then you could also call method(new C()) which doesn't implement I2, so you get into trouble.

So are there any other ways you could have done this?

P.S. : I don't really need to do this, it's mostly out of curiosity that I ask.

Andrei Fierbinteanu
  • 7,656
  • 3
  • 31
  • 45

4 Answers4

30

Create a third interface I3 extends I1 and I2. Then class A and B both implement I3, and the generic method accepts I3.

That's perhaps the only way to do it.

Sripathi Krishnan
  • 30,948
  • 4
  • 76
  • 83
  • 8
    I sort of realized this after I asked the question, though if you have more than two interfaces, and you want to mix and match those for different methods, it may become a pain creating a child interface for every combination you want to use. I was thinking more along the lines of having a method like `method (I1 & I2 param)` or some other way of saying the parameter implements multiple interfaces on the go (without creating a new class/interface) – Andrei Fierbinteanu Jun 24 '10 at 08:22
  • I don't think this good in design viewpoint. Please see my answer. – hqt Apr 30 '16 at 13:32
18

I don't think above answers are good under design viewpoint. When you make an interface, you want to make sure caller object has responsibility for some actions defined in that interface. So there are two solutions discussing above, and I will tell why those solutions aren't good in design viewpoint.

1. make one interface extends both two interfaces:

public interface IC extends IA,IB {
   // empty method here
}

Above code is non-sense. You define a separate interface just to combine other interfaces, and inside there aren't any new methods. You add no value to IC instead of combine two interface IA and IB. And some situations, this way will make your code "little fun" when you cannot find the suitable name for third interface. This situation will lead to some interface name such as IReadableAndWriteable or ISomethingAndSomethingAndAnotherThing

2. type cast inside method:

public void methodA(IA object) {
   if (object instance of IB) {
     ((IB)(object)).someMethod()
}

This way is nonsense too. Why the input parameter is IA then you must execute some action from interface IB? Under programmer viewpoint, there is no way to know that except from reading your document. That's not good for designing a function for other people use.

True solution:

Above solutions there is another problem in design: You force programmer use one object that has responsibility for two interfaces. What is the problem if programmer doesn't want to do this. They want to use two different concreted class for each different interfaces for easier testing, clean code? They cannot.

You should make two different parameters in your method signature:

public void exampleMethod(IA object1, IB object2) {
   object1.someMethod()
   object2.someMethod()
}

And for calling above method, you put same parameter inside(if programmer use same object). They also can put different objects too.

public void caller() {
   IC object3 = new C(); // C is the class implements both IA and IB
   exampleMethod(object3, object3);
   IA objectA = new A();
   IB objectB = new B();
   exampleMethod(objectA, objectB);       
}

Hope this help :)

hqt
  • 29,632
  • 51
  • 171
  • 250
  • 2
    Sorry I wake up an old topic, but I think the addition is worth it. I really think this answer is the best one. However, for the point 1, whether or not it makes sense is rather subjective (it can make sense as a temporary solution, at least), but there is a really objective and practical case which shows that it is not a good design: if you implement a class which extends both the relevant interfaces but *not* the interface which combine them, then you cannot use it in a method which asks for the combination interface, although it respects the initial contract. – Matthieu Mar 21 '17 at 07:51
  • 2
    I cannot edit the previous answer, so I add another one: the idea of making a combined interface is either not good or incomplete. It should not be a mere interface, but a wrapper: if you get your implementation from an external library, but want any implementation of the two interfaces to be usable so you don't want to be limited by the lib either, then you need a wrapper, or an adapter if you prefer. This solution ensures that you actually have both interfaces associated to the same instance, while the post of hqt above does not allow to ensure such constraint, which might still be worth. – Matthieu Mar 21 '17 at 08:17
2

Before Java 1.5 there is IMO no solution to achieve such type-sefety at compile-time. But there is a soultion at runtime using "instanceof".

public void method(Object o) {
  if (!(o instanceof I1))
    throw new RuntimeException("o is not instance of I1");

  if (!(o instanceof I2))
    throw new RuntimeException("o is not instance of I2");

  // go ahead ...
}
Braincompiler
  • 186
  • 1
  • 8
  • Well if you call `method(new C())` for my non-generic example in the question you'll get a `ClassCastException` when casting to `I2` to call `bar()`, so there's not much improvement here. – Andrei Fierbinteanu Jun 24 '10 at 08:27
  • Nope, you will get a RuntimeException before, because the check of "(o instanceof I2)" evaluates to false ;) Well I guess the suggestion of sri maybe much more better :) Because you won't get the risk of a runtime exception as with my suggestion because the compiler will fail before. – Braincompiler Jun 24 '10 at 08:45
2

sri is the best answer if you had permission to change the signature of A and B. However, if you did not have permission, then you could have done:

public void method(I1 param1 , I2 param2) { // unpopular classes that do not implement I3 must use this method
  param1.foo();
  param2.bar();
}
public void method(I3 param){ // I hope everybody implements I3 when appropriate
  param.foo();
  param.bar();
}
public void method(A param){// A is a popular class
  method(param,param);
}
public void method(B param){// B is a popular class
  method(param,param);
}

Of course, now just use generics.

Community
  • 1
  • 1
emory
  • 10,725
  • 2
  • 30
  • 58
  • Yes this would work, but if I1 is something like Comparable, I2 something like Serializable which are widely used, having a method for each Type that implements both (that calls the private one) might be a bit of a challenge. When I thought about the question, I just gave A and B as examples, I wouldn't really care what they are when calling the method (the only thing that mattered was that they implement those interfaces). And in fact if `method()` might be an API method, exposed for others to use, hard coding the classes that can use it like that would be a problem. – Andrei Fierbinteanu Jun 24 '10 at 11:22
  • Then a better choice would be to make the private method public and then some convenience methods for the classes of most interest - which could include the interface sri's I3 interface. – emory Jun 24 '10 at 12:10