Generics - makstron/info GitHub Wiki
-
Коваріантність - це збереження ієрархії успадкування вихідних типів у похідних типах у тому самому порядку. Наприклад, якщо
Cat- це підтипAnimal, тоList<Cat>- це підтипList<Animal>. Отже, з урахуванням принципу підстановки можна виконати таке присвоєння:List<Animal> = List<Cat> -
Контраваріантність - це звернення ієрархії вихідних типів на протилежну в похідних типах. Наприклад, якщо
Cat- це підтипAnimal, тоList<Animal>- це підтипList<Cat>. Отже, з урахуванням принципу підстановки можна виконати таке присвоєння:List<Cat> = List<Animal> -
Інваріантність - відсутність успадкування між похідними типами. Якщо
Cat- це підтипAnimal, тоList<Cat>не є підтипомList<Animal>іList<Animal>не є підтипомList<Cat>.
Дженеріки інваріантні
Generics не завжди інваріантні
PECS (Producer Extends Consumer Super)
class A { }
class B extends A { }
class C extends B { }
// Container
class S<V> {
private V value;
public V get() { return value; }
public void set(V value) { this.value = value; }
}extends - дозволяє тільки отримувати НЕ присвоювати
get() - Дозволено. Поверне щось, що є спадкоємцем B. Тобто що б метод get не повернув - це щось можна записати в змінну типу B.
S<? extends B> s;
B v = s.get(); // Значення типу ? extends B завжди можна записати в змінну типу Bset() - заборонено. В s може міститись колекція обєктів нащадків В наприклад С. Обєкт В не можна кастувати до його нащадка С. Відповідно в колекцію s не модна присвоїти В.
S<? extends B> s = new S<C>(); // можна присвоїти `С` в `В` тому що `extends B`
s.set(new B()); // Помилка - значення типу B не може бути передано як параметр типу Csuper - дозволяє тільки присвоювати НЕ отримувати
...........