Consider the following classes:
interface Notifiable {
}
class NotifiableImpl1 implements Notifiable {
}
class NotifiableImpl2 implements Notifiable {
}
class NotifiableImpl3 implements Notifiable {
}
It is normal that the following code works:
Set<Notifiable> set = new HashSet<>();
set.add(new NotifiableImpl1());
set.add(new NotifiableImpl2());
set.add(new NotifiableImpl3());
However, the following code does not work:
Set<? extends Notifiable> set2 = new HashSet<>();
set2.add(new NotifiableImpl1());
set2.add(new NotifiableImpl2());
set2.add(new NotifiableImpl3());
I understand it does not work, because it should only be possible to add one concrete subtype of Notifiable to set2, but how does it come then, that the following code also does not work?
Set<? extends Notifiable> set2 = new HashSet<>();
set2.add(new NotifiableImpl1());
And maybe more interesting, why does the following work?
Set<Notifiable> set = new HashSet<>();
set.add(new NotifiableImpl1());
set.add(new NotifiableImpl2());
set.add(new NotifiableImpl3());
Set<? extends Notifiable> set3 = set;
 
     
    