How to make a Java class that implements one interface with two generic types?

I have a generic interface

public interface Consumer<E> {
    public void consume(E e);
}

I have a class that consumes two types of objects, so I would like to do something like:

public class TwoTypesConsumer implements Consumer<Tomato>, Consumer<Apple>
{
   public void consume(Tomato t) {  .....  }
   public void consume(Apple a) { ...... }
}

Apparently I can't do that.

I can of course implement the dispatch myself, e.g.

public class TwoTypesConsumer implements Consumer<Object> {
   public void consume(Object o) {
      if (o instanceof Tomato) { ..... }
      else if (o instanceof Apple) { ..... }
      else { throw new IllegalArgumentException(...) }
   }
}

But I am looking for the compile-time type-checking and dispatching solution that generics provide.

The best solution I can think of is to define separate interfaces, e.g.

public interface AppleConsumer {
   public void consume(Apple a);
}

Functionally, this solution is OK, I think. It's just verbose and ugly.

Any ideas?


Consider encapsulation:

public class TwoTypesConsumer {
    private TomatoConsumer tomatoConsumer = new TomatoConsumer();
    private AppleConsumer appleConsumer = new AppleConsumer();

    public void consume(Tomato t) { 
        tomatoConsumer.consume(t);
    }

    public void consume(Apple a) { 
        appleConsumer.consume(a);
    }

    public static class TomatoConsumer implements Consumer<Tomato> {
        public void consume(Tomato t) {  .....  }
    }

    public static class AppleConsumer implements Consumer<Apple> {
        public void consume(Apple a) {  .....  }
    }
}

If creating these static inner classes bothers you, you can use anonymous classes:

public class TwoTypesConsumer {
    private Consumer<Tomato> tomatoConsumer = new Consumer<Tomato>() {
        public void consume(Tomato t) {
        }
    };

    private Consumer<Apple> appleConsumer = new Consumer<Apple>() {
        public void consume(Apple a) {
        }
    };

    public void consume(Tomato t) {
        tomatoConsumer.consume(t);
    }

    public void consume(Apple a) {
        appleConsumer.consume(a);
    }
}

Because of type erasure you can't implement the same interface twice (with different type parameters).


Here's a possible solution based on Steve McLeod's one:

public class TwoTypesConsumer {
    public void consumeTomato(Tomato t) {...}
    public void consumeApple(Apple a) {...}

    public Consumer<Tomato> getTomatoConsumer() {
        return new Consumer<Tomato>() {
            public void consume(Tomato t) {
                consumeTomato(t);
            }
        }
    }

    public Consumer<Apple> getAppleConsumer() {
        return new Consumer<Apple>() {
            public void consume(Apple a) {
                consumeApple(t);
            }
        }
    }
}

The implicit requirement of the question was Consumer<Tomato> and Consumer<Apple> objects that share state. The need for Consumer<Tomato>, Consumer<Apple> objects comes from other methods that expect these as parameters. I need one class the implement them both in order to share state.

Steve's idea was to use two inner classes, each implementing a different generic type.

This version adds getters for the objects that implement the Consumer interface, which can then be passed to other methods expecting them.


At least, you can make a small improvement to your implementation of dispatch by doing something like the following:

public class TwoTypesConsumer implements Consumer<Fruit> {

Fruit being an ancestor of Tomato and Apple.


just Stumbled upon this. It just happened, that I had the same Problem, but I solved it in a different way: I just created a new Interface like this

public interface TwoTypesConsumer<A,B> extends Consumer<A>{
    public void consume(B b);
}

unfortunately, this is considered as Consumer<A> and NOT as Consumer<B> against all Logic. So you have to create a small Adapter for the second consumer like this inside your class

public class ConsumeHandler implements TwoTypeConsumer<A,B>{

    private final Consumer<B> consumerAdapter = new Consumer<B>(){
        public void consume(B b){
            ConsumeHandler.this.consume(B b);
        }
    };

    public void consume(A a){ //...
    }
    public void conusme(B b){ //...
    }
}

if a Consumer<A> is needed, you can simply pass this, and if Consumer<B> is needed just pass consumerAdapter