2016-11-17 5 views
2

Почему этот код компиляции:Почему ArrayList <E> конструктор позволяет необработанного параметр ArrayList

ArrayList strings = new ArrayList(); 
strings.add("s1"); 
strings.add("s2"); 

ArrayList<Integer> numbers = new ArrayList<Integer>(strings); 

Учитывая, что конструктор в вопросе ожидает Collection<? extends E> где E в данном случае Integer? Как объекты, содержащиеся в необработанном типе ArrayList, являются подклассом E? Или есть какая-то скрытая магия компилятора, которая позволяет это для устаревших целей?

+1

Я думаю, что это из-за совместимости. Поскольку компилятор не может знать, какие объекты находятся в «строках», он предполагает, что в нем есть правильные. Если компилятор вел себя по-другому (и не допустил бы этого), переход от (старых) не общих правил с использованием кода к дженерикам был бы почти невозможным. –

+0

Это всего лишь один экземпляр известного преобразования исходного типа: 'Список numbers = new ArrayList();'. –

ответ

2

Проверьте ArrayList конструктор:

public ArrayList(Collection<? extends E> c) { 
    elementData = c.toArray(); 
    if ((size = elementData.length) != 0) { 
     // c.toArray might (incorrectly) not return Object[] (see 6260652) 
     if (elementData.getClass() != Object[].class) 
      elementData = Arrays.copyOf(elementData, size, Object[].class); 
    } else { 
     // replace with empty array. 
     this.elementData = EMPTY_ELEMENTDATA; 
    } 
} 

elementData является массив объекта:

transient Object[] elementData; 

Так новый ArrayList(Collection<? extends E> c) будет принимать все Collection, не забочусь E типа

Это будет бросать ClassCastExceptionwhen если воспользуемся этим:

Integer i= numbers.get(1); 
+0

Это не объясняет, как удовлетворяются элементы в сыром 'ArrayList'? расширяет E'. –

1

Компилятор должен дать вам это предупреждение:

безопасности Тип: Выражение типа ArrayList необходимо непроверенную преобразование, чтобы соответствовать Collection<? extends Integer>

о том, что есть что-то не так с заданный аргумент (строки).

Вы также должны получить это исключение при попытке запустить код:

java.lang.ClassCastException: java.lang.String не может быть приведен к java.lang.Integer

Причина, по которой вы не получаете ошибку компиляции, состоит в том, что строки ArrayList не определены правильно, вы опустили тип String. Поэтому компиляция может только догадываться, что есть что-то. Изменение кода

ArrayList<String> strings = new ArrayList<String>(); 

и вы получите ошибку компиляции

Конструктор ArrayList<Integer>(ArrayList<String>) не определен