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>.

Дженеріки інваріантні



Wildcards

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; }
}

Коваріантність Generics

extends - дозволяє тільки отримувати НЕ присвоювати

get() - Дозволено. Поверне щось, що є спадкоємцем B. Тобто що б метод get не повернув - це щось можна записати в змінну типу B.

S<? extends B> s;
B v = s.get(); // Значення типу ? extends B завжди можна записати в змінну типу B

set() - заборонено. В s може міститись колекція обєктів нащадків В наприклад С. Обєкт В не можна кастувати до його нащадка С. Відповідно в колекцію s не модна присвоїти В.

S<? extends B> s = new S<C>(); // можна присвоїти `С` в `В` тому що `extends B`
s.set(new B()); // Помилка - значення типу B не може бути передано як параметр типу C

Контраваріантність Generics

super - дозволяє тільки присвоювати НЕ отримувати

...........

⚠️ **GitHub.com Fallback** ⚠️