I ran into this problem recently when I was playing around. Basically, I wanted to make a central class where consumers of a certain type could register themselves. Something then publishes objects for the consumers, and only those consuming the published type should receive it.
The entire program can be summarised to this:
public class Main
{
    public interface Fruit
    {
    }
    public class Apple implements Fruit
    {
    }
    public class Banana implements Fruit
    {
    }
    public interface FruitConsumer<T extends Fruit>
    {
        public void consume(T fruit);
    }
    public class Consumers<T extends Fruit>
    {
        Map<Class<T>, Collection<FruitConsumer<T>>> consumers = new HashMap<>();
        public void register(Class<T> clazz, FruitConsumer<T> consumer)
        {
            consumers.putIfAbsent(clazz, new HashSet<>());
            consumers.get(clazz).add(consumer);
        }
        public void consume(T fruit)
        {
            Collection<FruitConsumer<T>> cons = consumers.get(fruit.getClass());
            for (FruitConsumer<T> c : cons)
            {
                c.consume(fruit); // <-- Breaks if T is Apple
            }
        }
    }
    public class BananaConsumer implements FruitConsumer<Banana>
    {
        void register(Consumers c)
        {
            c.register(Banana.class, this);
            c.register(Apple.class, this); // <-- Why does this work?
        }
        @Override
        public void consume(Banana banana)
        {
            System.out.println("Mmm, banana");
        }
    }
    public static void main(String... args)
    {
        Main main = new Main();
        main.run();
    }
    private void run()
    {
        Consumers consumers = new Consumers<>();
        BananaConsumer bananaConsumer = new BananaConsumer();
        bananaConsumer.register(consumers);
        Banana banana = new Banana();
        consumers.consume(banana);
        Apple apple = new Apple();
        consumers.consume(apple);
    }
}
Now, I think I understand why this crashes. There is no way for the compiler to know that the T in the Consumers.registermethod is the same T, for both parameters. The compiler can only enforce that both arguments meets the requirement T extends Fruit. I want to remember being able to use a similar code structure in C++, so there has to be something the two languages does different. Is my assumption here correct?
Also, what would be the correct way of going about this? I would like different consumers of subtypes of Fruit to be able to register themselves, and receive only those fruits they enlist themselves as consumers of. Also, I would like some safety in what you can register yourself as a consumer off (I noticed that this code works as long as no one registers themselves "wrong").
Lastly, what is the name of this phenomena? Basically, what do I google to learn more about this.
 
     
     
    