Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

People also ask

Can a class implements 2 interfaces?

Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.

Can a class implement different instantiations of the same generic interface if so give an example?

Can I use different instantiations of a same generic type as bounds of a type parameter? No, at most one instantiation of the same generic type can appear in the list of bounds of a type parameter.

Can an interface have a generic type Java?

Java Generic Classes and SubtypingWe can subtype a generic class or interface by extending or implementing it.


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


In Functional style it is quite easy do this without implementing the interface and also it does the compile time type checking.

Our functional interface to consume entity

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

our manager to process and consume entity appropriately

public class Manager {
    public <E> void process(Consumer<E> consumer, E entity) {
        consumer.consume(entity);
    }

    public void consume(Tomato t) {
        // Consume Tomato
    }

    public void consume(Apple a) {
        // Consume Apple
    }

    public void test() {
        process(this::consume, new Tomato());
        process(this::consume, new Apple());
    }
}