2013-11-23 3 views
0

В Java Integer расширяет NumberJava дженериков странное поведение

Тогда следующий код компилирования:

List<Number> list1 = null; 
List<? super Integer> list2 = null; 
list2 = list1; 

Хотя этот код не компиляции:

List<? super Number> list1 = null; 
List<? extends Integer> list2= null; 
list1 = list2; 

Вопрос заключается в Зачем?

+2

Вы заметили, что ваши назначения в обоих кодах отменены. Измените первый код на 'list1 = list2', и он тоже не будет компилироваться. –

ответ

5

Давайте посмотрим, что пойдет не так, если бы составили:

// Suppose list1, and list2 are initialized like this 
List<? super Number> list1 = new ArrayList<Object>(); // valid assignment 
List<? extends Integer> list2 = new ArrayList<Integer>(); // valid 

// had this been valid, list1 and list2 both point to ArrayList<Integer> 
list1 = list2; 

// This is fine, as list1 declared type is `List<? super Number>` 
list1.add(new Float(2.4f)); 

// The below code will compile fine, as list2.get(0) type is Integer. 
// But it would throw ClassCastException at runtime. 
Integer in = list2.get(0); 

Таким образом, чтобы избежать его выполнения, компилятор выдаст ошибку во время компиляции.

Для первого случая, однако, вы каким-то образом изменили назначение, поэтому сравнение между двумя кодами не имеет смысла. Измените первый код на:

List<Number> list1 = null; 
List<? super Integer> list2 = null; 
list1 = list2; 

И он тоже не сработает.

Кроме того, реверсирование задания во втором коде также скомпрометирует код.

Некоторые пояснения:

То, что вы должны помнить, есть ссылка супер класс может указывать на объект подкласса, но не наоборот. Если все списки, которые могут быть захвачены с помощью преобразования из list1, также являются захваченными конвертируемыми из объявленного типа list2, тогда назначение list2 = list1 было бы правильным, иначе оно не скомпилировалось.

Для первого кода:

  • List<? super Integer> могут быть захвата преобразуются в следующие списки:
    • List<Integer>
    • List<Number>
    • List<Object>
    • List<Serializable>

Поскольку List<Number> есть в списке, так что назначение list2 = list1 справедливо, как list1 может указывать только на List<Number>. Но обратное присвоение list1 = list2 недействительно, так как List<Integer> не является подтипом List<Number>.

Аналогично, для 2-го кода:

  • List<? super Number> может быть захват преобразуется в:

    • List<Object>
    • List<Serializable>
    • List<Number>
  • List<? extends Integer> может быть захват преобразуется в:

    • List<Integer>

Поскольку List<Integer> не захват преобразуемых из List<? super Number>, так list1 = list2 недействителен.

Кроме того, поскольку List<Object> и все другие списки не являются отключаемыми с List<? extends Integer>, поэтому list2 = list1 также недействителен.

+0

Да, но вопрос в том, почему один работает, а другой не – Bohemian

+0

@Bohemian Просто увидел, что его первый код имеет назначение в другом направлении. Итак, это скомпилируется. Изменение этого параметра на 'list1 = list2' завершится неудачно. –

+0

Достаточно хорошо +1! – Bohemian

0

(1) В первом примере List<Number> «захвачен» от List<? super Integer>. A List<Number> - List<? super Integer>.

(2) Но во втором примере List<? extends Integer> является не снято List<? super Number>.

Например, вы можете добавить Number с до List<? super Number>, но вы не можете добавить Непро- IntegerNumber с до List<? extends Integer>.

List<? super Number> list1 = new ArrayList<Number>(); 
list1.add(0.5);  //okay 
List<? extends Integer> list2 = new ArrayList<Integer>(); 
list2.add(0.5); //not okay 

Таким образом, вы не можете назначить list1 быть list2, поскольку list2 не поддерживает все, что тип list1 должен.

+0

Я не пытаюсь добавить число в список . Я пытаюсь добавить Integer в List и не работает –

+0

Но @Babibu, если вы хотите установить 'list1' как' list2', тип 'list1' должен поддерживать все операции' list2'. –

+0

Никто ничего не добавляет, есть попытка выполнить задание. –

Смежные вопросы