2013-04-25 2 views
12
List list = new ArrayList<String>() ; 
list.add(1) ; 
Integer hello = (Integer) list.get(0) ; 
System.out.println(hello); 

Приведенный выше код содержит ссылку типа Список со ссылкой на экземпляр ArrayList от типа Строка. Когда выполняется строка list.add(1), не 1, добавленный в ArrayList (типа String)? Если да, то почему это разрешено?Как можно добавить Integer в String ArrayList?

+0

Что дает ваш println? – wazaminator

+0

Протестировано; Он печатает 1^ –

+0

Какую IDE вы используете, чтобы написать этот код? А компилятор компилировать его? Мне кажется странным, что ваш код даже компилируется. – nikkatsa

ответ

14

Вы использовали стирание типа, что означает, что вы проигнорировали ранее установленные общие проверки. Вы можете уйти от этого, так как это значит, что generics - это функция времени компиляции, которая не проверяется во время выполнения.

То, что вы так же, как

List list = new ArrayList() ; 
list.add(1) ; 
Integer hello = (Integer) list.get(0) ; 
System.out.println(hello); 

или

List<Integer> list = new ArrayList<Integer>() ; 
list.add(1) ; 
Integer hello = list.get(0); // generics add an implicit cast here 
System.out.println(hello); 

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

Интересно, что вы можете сделать это

List<String> strings = new ArrayList<String>(); 
@SuppressWarnings("unchecked"); 
List<Integer> ints = (List) strings; 
ints.add(1); 

System.out.println(strings); // ok 
String s= strings.get(0); // throws a ClassCastException 
+0

Почему компилятор не мешает мне делать Список list = new ArrayList (); ? В идеале это должно было позволить только одно из двух вышеупомянутых. –

+0

Eclispe выдает предупреждение, когда вы делаете 'List list = new ArrayList ();'. Я всегда, хотя компилятор тоже это сделал. –

+0

Прекрасная вещь, называемая обратной совместимостью. Вы должны уметь назначать общие коллекции методам, которые не были написаны для дженериков. Надеюсь, в один прекрасный день эта функция будет удалена, но я в этом сомневаюсь., –

-4

Нет, потому что Java видит 1 как целое. Вам нужно будет преобразовать ваш номер как строку сначала с Integer.toString(n)

+0

Это компилируется и запускается ... –

-3

Попробуйте

List.add(Integer.toString(1)); 

Вы также можете попробовать этот

List list = new ArrayList<Object>() ; 

Если нет необходимости, что ArrayList должен быть Список_массивов от строки

+1

Это не отвечает на вопрос вообще –

11

Проблема в том, что переменная list имеет тип raw, и вы можете добавлять в этот список объекты любого типа. Чтобы решить эту проблему, просто объявить его как List из String-х:

List<String> list = new ArrayList<String>() ; 
2

Он собирает, потому что объявление List list использует необработанный тип List, не связанный тип List<String>. Вторая строка компилируется, потому что ваша переменная list может принимать что угодно. Третья строка компилируется, потому что list.get(0) возвращает Object. В четвертой строке нет причин для отказа.

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

List<String> list = new ArrayList<>(); 

Ваша ошибка была бы поймана во время компиляции.

2

Когда вы объявляете список вроде этого: List list = new ArrayList<String>() ;

Вы используете то, что называется тип Raw. Это тип, который имеет общий тип типа, например List, но вы его не смогли его предоставить. Если вы проверите предупреждения компилятора, вы увидите, что это говорит вам об этом. Смешивание параметризованных типов с необработанными типами обычно считается ошибкой программирования.Это нормально:

List<String> list = new ArrayList<String>() ;

и это нормально (но устаревшие):

List list = new ArrayList();

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

Проблема в том, что дженерики проверяются только во время компиляции, и вы сказали компилятору List, а не List<String>, поэтому он позволит вам положить что угодно, что вы хотите там! Тот факт, что правая сторона имеет параметр, на самом деле ничего не значит, это тип фактической ссылки, которая имеет значение для компилятора.

-1

Да ... 1 добавлен в Array, потому что Java, как и другие языки, реализует неявное (автоматическое) преобразование (литье) типов данных примитивов.

Более подробная информация здесь Conversions and Promotions

+0

'String' не примитив и не имеет автоматических преобразований. –

0
List list = new ArrayList<String>() ; // WARNING!!! 

Опасное Список относится к безопасному ArrayList

list.add(1) ; // WARNING!!! 

Целое число (INT 1 преобразуется в целое Autoboxing) не строка добавляется в список

Integer hello = (Integer) list.get(0) ; 

Кастинг необходим, так как небезопасный список ca n содержит что угодно.

System.out.println(hello); 

Integer.toString() называется

Когда линия list.add (1) выполняется, не 1 добавляется к ArrayList (типа String)?

Да. Целое число было добавлено в ArrayList, который должен содержать String.

Если да, то почему это разрешено?

Обратная совместимость. Java должна поддерживать предварительные коды.

Список списков; означает, что он небезопасен, поэтому вы можете сделать что-либо с ним, и упомянутый ArrayList() должен это терпеть.

Мораль: Не игнорируйте предупреждения компилятора, в противном случае Integer может войти в массив ArrayList, который должен содержать строки.

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