Если создать переменную типа List<Number>, то ей нельзя будет присвоить ссылку на экземпляр ArrayList<Integer> или ArrayList<Double>. Вы можете присвоить ей только экземпляр ArrayList<Number> ( либо LinkedList<Number> ):
1 2 3 4 5 6 7 |
List<Number> a = new ArrayList<Number>(); // МОЖНО List<Number> b = a; // МОЖНО List<Number> c = new ArrayList<Number>(); // МОЖНО List<Number> d = new ArrayList<Integer>(); // НЕЛЬЗЯ!!!!! |
List<Number> и List<Integer> — это совершенно разные, несовместимые объекты, несмотря на то что Integer наследуется от Number.
Однако переменной типа List<?> можно присвоить как ArrayList<Number>, так и ArrayList<Integer>.
1 2 3 4 5 6 7 |
List<Number> a = new ArrayList<Number>(); List<Integer> b = new ArrayList<Integer>(); List<?> c = a; // OK List<?> d = b; // OK List<?> e = new ArrayList<Number>(); // OK List<?> f = new ArrayList<Integer>(); // OK |
List<?> является общим предком для List<Number> и List<Integer>.
Аналогичным образом List<? extends Number> является предком для List<? extends Integer>:
1 2 |
List<? extends Integer> a = new ArrayList<>(); List<? extends Number> b = a; // OK |
Также List<? super Integer> является предком для List<? super Number>:
1 2 |
List<? super Number> a = new ArrayList<>(); List<? super Integer> b = a; // OK |
Это, наверное, трудно так сразу понять и запомнить, но как только вы осознаете это, то это начнёт выглядеть абсолютно логично. На первых порах можете просто выучить, что наследование обобщённых типов работает именно так, вдруг где пригодится.