/ / Кастинг на загальну змінну - java, generics, кастинг

Лиття до загальної змінної - java, generics, casting

Я розумію загальний і кастинг, але не розумію загальний кастинг. Я думав, що я можу призначати лише певний тип вгору або вниз через дерево спадкування, але це довів мене неправильно:

ArrayList<?> cislo = (ArrayList<? extends Number>) new ArrayList<Integer>();

Це може бути не найкращим прикладом, але, сподіваюся, ви зрозумієте мою думку. Як це працює? До якого типу його віддати?

Відповіді:

4 для відповіді № 1

Акторський склад зайвий.

Завдання

ArrayList<?> list = new ArrayList<Integer>();
ArrayList<? extends Number> list2 = new ArrayList<Integer>();

не вимагайте явного кастингу.

Замісні типи - це "більш загальні" / "менш специфічні" типи, ніж конкретні типи, і види верхнього обмеження (люблю ? extends Number) більш конкретні, ніж безмежні (?)

Більш детальну інформацію про співвідношення між типовими символами можна знайти в розділі Підручник Oracle з марок та підтипів.

Відповідна частина JLS, яка це вказує, є 4.10.2. Підтипи серед типів класів та інтерфейсів

З огляду на загальне оголошення типу C (n> 0), прямі супертипи параметризованого типу C, де Ti (1 ≤ i ≤ n) - це такі:

  • D, де D - це загальний тип, який є прямим супертипом родового типу C, а θ - заміщення [F1: = T1, ..., Fn: = Tn].
  • C, де Si містить Ti (1 ≤ i ≤ n) (§4.5.1).

[...]

на які посилаються 4.5.1. Аргументи типу параметризованих типів

Аргумент типу T1, як кажуть, містить іншийаргумент типу T2, записаний T2 <= T1, якщо сукупність типів, позначених T2, є, мабуть, підмножиною набору типів, позначених T1 під рефлексивним та транзитивним закриттям наступних правил (де <: позначає підтипи (§4.10) ):

  • ? розширює T <=? розширює S, якщо T <: S

  • ? розширює T <=?

[...]

Так за цим визначенням ArrayList<? extends Number> є супертипом ArrayList<Integer> і ArrayList<?> є супертипом будь-якого ArrayList<> крім сировинного типу.

Присвоєння змінної типу, що є супертипом, не вимагає кастингу.


Кастинг необхідний, якщо ви хочете призначити щось іншого типу:

Object list = new ArrayList<Integer>();
//...somewhere else - the compiler does not know that list is always an ArrayList, but we tell it that we know what we are doing
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but works

Після цього акторського складу ви можете, наприклад, отримуйте елементи зі списку та розглядайте їх як Numberс. Оформлення не вдасться виконати, якщо призначити щось інше list посилання, яке не є підтипом List<? extends Number>

    Object list = new HashSet<Integer>();
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning

не вдається під час кидання

java.lang.ClassCastException: java.util.HashSet cannot be cast to java.util.List


Проблеми починають виникати, коли загальний тип не відповідає:

List<String> stringList = new ArrayList<String>();
stringList.add("hi");
Object list = stringList;
List<? extends Number> numbers = (List<? extends Number>) list; //unchecked cast warning, but (sadly) works

Number n = numbers.get(0); //fails: java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number

Це відбувається тому, що під час виконання, стирання типів списків відповідає. Дивись також навчальний посібник зі стирання