2

So, yes I've seen this question. However, what if I had two interfaces, IA and IB, but I wanted a parameter to a function (or property of a class) to be:

public void (<? extends IA, IB> someClass) {
//...
}

Is there a way to do this without using generics?

EDIT:

I've realized that what I really want is Duck Typing, like in Python. I just didn't get my words out right. With that in mind, clearly there is no real way to do this in Java. I accepted this answer, but then realized that the input would have to have the signature of that new interface to work. However, he did meet my awkwardly-worded criteria :).

Community
  • 1
  • 1
daveslab
  • 10,000
  • 21
  • 60
  • 86

3 Answers3

6

This syntax works for a method that you want to pass something into that implements two interfaces IA and IB:

public <T extends IA & IB> void someMethod(T arg) {
    // ...
}

For a member variable of a class:

public class Example<T extends IA & IB> {
    private T value;

    // ...
}

(Why do you want to do this without generics?).

Jesper
  • 202,709
  • 46
  • 318
  • 350
  • A major difficulty arises if one wants to have multiple calls to `someMethod` store the passed-in `arg` values, all of which implement IA and IB, but may not have a common base type, in such a way that they can be later passed to a routine with similar constraints. The best one can do if one can't modify IA and IB is probably to define an abstract proxy class which implements IA and IB by calling abstract virtual methods and a derived concrete generic proxy class which holds an instance of a constrained generic type and implements of the interfaces' methods by calling them on that instance. – supercat Jan 12 '12 at 22:29
  • The problem with this approach is that the object which is stored will not be the one passed in, and there will be no way to retrieve the passed-in object in such a fashion as to satisfy the generic constraints. – supercat Jan 12 '12 at 22:30
  • Is there a way to do this without using `T`? The reason is that I'm not so much using it as an argument to a function as I am on a class property, and I can't have a class property which references `T` without having the class line declare it. – daveslab Jan 12 '12 at 23:34
  • @daveslab You can use generics on the method level: `public void foo (T someClass) { ... }` – emory Jan 14 '12 at 00:37
5
interface IAandIB extends IA, IB { }

public void Foo(IAandIB someClass) {
//...
}

Since interfaces can extend multiple other interfaces, you can just make an empty 'dummy interface' that extends both of them, and use it as the type to designate whenever both are required.

This works, but is not a catch-all solution as it requires you to modify every single class that implements IA and IB so they can work for this method, which is annoying at best and impossible in some situations. Unfortunately, I do not know of any other way to do this without generics.

Gordon Gustafson
  • 40,133
  • 25
  • 115
  • 157
  • 3
    I don't think that's right. The original poster wants a method whose parameter is any object whose class implements IA and also implements IB. In general, such a class won't implement IAB, so the object won't be able to be passed to this method. Please correct me if I've misunderstood your answer. – Dawood ibn Kareem Jan 12 '12 at 21:57
  • @DavidWallace You are understood, this solution is far from ideal because it requires modifying all the potential classes that could be passed to the method. I do not know if any other way to do this exists (without generics), but I am *far* from an expert in Java, and if there is a better solution I will gladly upvote it and delete this answer if necessary. :D – Gordon Gustafson Jan 12 '12 at 22:07
  • @CrazyJugglerDrummer There is a way to do this, see my answer. – Jesper Jan 12 '12 at 22:08
  • @Jesper I have upvoted your answer for being more feasible than mine, but as far as I know this is the only way to do this *without* generics as requested by the OP, although I agree that it is unlikely that there would arise any real-world situation where you wouldn't be able to. – Gordon Gustafson Jan 12 '12 at 22:11
1

Extending CrazyJugglerDrummer's answer

interface IAandIB extends IA, IB { }


public void Foo(IA a , IB b )
{
     if ( a != b )
     {
         throw new IllegalArgumentException ( ) ;
     }
     ClassLoader loader = IAandIB . class . getClassLoader ( ) ;
     Class < ? > [ ] interfaces = new Class < ? > [ IAandIB . class , IA . class , IB . class ] ;
     InvocationHandler handler = new InvocationHandler ( )
     {
           public Object invoke ( Object proxy , Method method , Object [ ] args ) throws Exception
           {
                 Object r = null ;
                 try
                 {
                      // since a==b, it should not matter whether we use a or b here.
                      r = method . invoke ( a , args ) ;
                 }
                 catch ( InvocationTargetException cause )
                 {
                       throw cause . getCause ( ) ;
                 }
                 catch ( Exception cause )
                 {
                       throw new RuntimeException ( cause ) ;
                 }
           }
     }
     IAandIB ab = ( IAandIB ) ( Proxy . newProxyInstance ( loader , interfaces , handler ) ) ;
     Foo ( ab ) ;
}

public void Foo(IAandIB someClass) {
//...
}
Community
  • 1
  • 1
emory
  • 10,725
  • 2
  • 30
  • 58