views:

44

answers:

3

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.

+4  A: 

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.

sri
Andrei Fierbinteanu
+2  A: 

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 ...
}
VuuRWerK
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
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.
VuuRWerK
+1  A: 

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.

emory
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
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