2017-01-03 16 views
2

Там две программы Почему работает первый код код? Я ожидал, что это бросить время выполнения исключение при обращении к элементам, как строка добавляется вместо IntegerДженерики во время выполнения

Аналогично .. Второй код throwing Run time Exception при доступе к элементу, хотя он может удобно добавлять Integer в arrayList, несмотря на то, что он удерживает String.

В обоих кодов, мы успешны в добавлении различных типов данных, но проблемы, кажется, появляются в то время как доступ к элементам

import java.util.ArrayList; 

public class Test { 
    public static void main(String[] args) { 

     ArrayList<Integer> arrayList = new ArrayList<>(); 
     Test.addToList(arrayList); 

     System.out.println(arrayList.get(0)); 
    } 

    public static void addToList(ArrayList arrayList) { 
     arrayList.add("i"); 

    } 
} 






import java.util.ArrayList; 

public class Test { 
    public static void main(String[] args) { 

     ArrayList<String> arrayList = new ArrayList<>(); 
     Test.addToList(arrayList); 

     System.out.println(arrayList.get(0)); 
    } 

    public static void addToList(ArrayList arrayList) { 
     arrayList.add(1); 

    } 
} 
+1

Почему это разрешено «добавлять» из-за определения функции - определенная вами функция не знает, какие типы 'arrayList' ожидает (или должна допускать) - как и для ошибки времени выполнения:' String' является классом, поэтому «ArrayList» хранит ссылки (вроде подобных адресов) - если вы пытаетесь получить доступ к ячейке памяти 1, она не содержит действительного объекта «String», поэтому вы получаете ошибку времени выполнения. – UnholySheep

+0

. Вы должны получать «ClassCastException» во время выполнения второго , – NewUser

+1

@UnholySheep Но я не уверен, что ваш комментарий объясняет, почему первый тоже не подведет. –

ответ

1

дженериков существуют только во время компиляции. Они удаляются из двоичного кода после компиляции, это называется стиранием типа. Это делается в основном по причинам обратной совместимости.

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

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

Однако, когда вы получаете доступ к объектам, используя get(), что-то происходит, происходит актерское происхождение.

ArrayList<String> list = new ArrayList<>(); 
list.add("Hello"); 
String s = list.get(0); 

Последняя строка переписывается:

String s = (String) list.get(0); 

Это не выполняется, если список не возвращает что-то типа String. Когда вы используете только общие данные в списке, он будет иметь только String s (или ваш код не будет компилироваться). Но, поскольку вы разрешили объект не String в списке, проверка типа приведения не будет выполнена.

3

В обоих случаях вы можете добавить элементы из-за type erasure. Во время выполнения класс не знает, что он был объявлен как new ArrayList<String>(), только что он был объявлен как new ArrayList().

В футляре println вступает в действие разрешение перегрузки времени компиляции. System.out является PrintStream, в котором есть несколько перегрузок для println. Среди них:

... 
void println(Object x); 
void println(String x); 

Компилятор Java выберет те из них, которые наиболее специфичны. В корпусе ArrayList<Integer> он первый, а в корпусе ArrayList<String> он второй. Как только он это сделает, как часть обработки стирания типа, он выдаст результат объекта raw ArrayList::get(int) на нужный тип, но только если это необходимо.

В случае вызова ArrayList<Integer> литой не требуется (ArrayList::get(int) возвращает объект, который точно такой, какой ожидает метод), поэтому javac опускает его. В случае вызова ArrayList<String>, -, поэтому javac добавляет его.То, что вы видите, как:

System.out.println(arrayList.get(0)); 

фактически компилируется:

System.out.println((String) arrayList.get(0)); 

Но элемент не является String, и это то, что приводит к ClassCastException.

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