Why is Set<? extends Foo<?>> allowed, but Set<Foo<?>> is not [duplicate]

  • A+

This question already has an answer here:

I want to know how generics work in this kind of situation and why Set<? extends Foo<?>> set3 = set1; is allowed but Set<Foo<?>> set2 = set1; is not?

import java.util.HashSet; import java.util.Set;  public class TestGenerics {     public static <T> void test() {         Set<T> set1 = new HashSet<>();         Set<?> set2 = set1;             // OK     }      public static <T> void test2() {         Set<Foo<T>> set1 = new HashSet<>();         Set<Foo<?>> set2 = set1;           // COMPILATION ERROR         Set<? extends Foo<?>> set3 = set1; // OK     } }  class Foo<T> {} 


Simply said, this is because Set<? extends Foo<?>> is covariant (with the extends keyword). Covariant types are read-only and the compiler will refuse any write action, like Set.add(..).

Set<Foo<?>> is not covariant. It does not block write or read actions.


Set<Foo<String>> set1 = new HashSet<>(); Set<Foo<?>> set2 = set1; // KO by compiler 

... is illegal because otherwise I could for example put a Foo<Integer> into set1 via set2.

set2.add(new Foo<Integer>()); // Whoopsie 


Set<Foo<String>> set1 = new HashSet<>(); Set<? extends Foo<?>> set3 = set1; // OK 

... is covariant (extends keyword), so it is legal. For example, the compiler will refuse a write operation like set3.add(new Foo<Integer>()), but accept a read operation like set3.iterator().

Iterator<Foo<String>> fooIterator = set3.iterator(); // OK set3.add(new Foo<String>()); // KO by compiler 

See these posts for a better explanation:


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: