Подтвердить что ты не робот

Почему возможно вернуть объект "неправильного типа" из параметризованного списка в Java?

Здесь фрагмент кода:

import java.util.*;
class Test
{
    public static void main(String[] args)
    {
        List<Integer> list = new ArrayList<>();
        addToList(list);
        Integer i = list.get(0); //#1 fails at run-time
        String s = list.get(0); //#2 fails at compile-time
        list.get(0); //#3 works fine
        System.out.println(list.get(0)); //#4 works fine, prints "string"
    }
    static void addToList(List list){
        list.add("string");
    }
}

Я понимаю, почему можно вставить объект класса String в параметризованный список.

Похоже, я понимаю, почему код, помеченный #1 и #2, не работает.

Но почему работают #3 и #4? Насколько я понимаю, компилятор добавляет соответствующие отбрасывания после стирания типа, поэтому, когда я вызываю list.get(0), этот метод должен возвращать объект, ранее заданный в Integer. Итак, почему ClassCastException не встречается на # 3 и # 4 во время выполнения?

4b9b3361

Ответ 1

# 3 работает, потому что объект, возвращаемый get(int), игнорируется. Все, что хранится в позиции 0, возвращается, но поскольку никакого переноса не происходит, ошибка не возникает.

# 4 работает отлично по той же причине: объект, созданный get(0), рассматривается как подкласс java.lang.Object в println, потому что вызывается toString. Поскольку toString() доступен для всех объектов Java, вызов завершается без ошибок.

Ответ 2

Сначала вы можете добавить строку в List<Integer>. В методе

static void addToList(List list){

используется необработанный тип. Необработанные типы существуют исключительно для совместимости со старыми версиями Java и не должны использоваться в новом коде. В рамках метода addToList компилятор Java не знает, что list должен содержать только целые числа, и поэтому он не жалуется, когда к нему добавляется String.

Что касается различного поведения двух операторов. Integer i = list.get(0) не работает во время компиляции, потому что Java считает, что list содержит только Integer s. Только во время выполнения получается, что первый элемент list не является целым, поэтому вы получаете ClassCastException.

String s = list.get(0) выходит из строя во время компиляции, потому что компилятор Java предполагает, что list содержит только целые числа, поэтому предполагается, что вы попытаетесь присвоить целочисленное значение ссылке.

Просто list.get(0) не сохраняет результат вызова метода. Поэтому ни во время компиляции, ни во время выполнения нет причин для отказа.

Наконец, System.out.println(list.get(0)) работает, потому что System.out является PrintStream и имеет метод println(Object), который может быть вызван с аргументом Integer.

Ответ 3

Если вы посмотрите на метод ArrayList#get. Это:

public E get(int index) {
   //body
}

Но во время выполнения это на самом деле:

public Object get(int index) {
       //body
}

Итак, когда вы делаете Integer i = list.get(0); Компилятор преобразует его в:

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

Теперь во время выполнения list.get(0) возвращает тип Object (на самом деле String). Теперь он пытается преобразовать String => Integer, и он терпит неудачу.

3

Потому что это просто:

list.get(0)

Компилятор добавляет приведение к чему-либо. Так оно и есть, list.get(0).

4

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

list.get(0) возвращает тип Object. Таким образом вызывается метод .

Помните println (Object x), который вызывается, а не println (String x).

Ответ 4

4: Вызывается перегрузка System.out.println(Object), поскольку Integer <= _ T Object (read: Integer is-a Object). Обратите внимание: list.get(int) возвращает объект во время выполнения, поскольку параметр типа стирается. Теперь прочитайте

http://docs.oracle.com/javase/tutorial/java/generics/erasure.html

который сообщает вам: "Вставьте тип приведения, если необходимо, чтобы сохранить безопасность типа". Поскольку тип-тип не требуется от Object to Object, исключение ClassCastException не может быть выполнено.

По той же причине нет типа, отличного от 3, однако могут возникнуть побочные эффекты вызова метода, из которых List.get не имеет.

Ответ 5

Листы применяются к типу возврата get, а не к add, который вводит загрязнение. В противном случае вы получите либо ошибку времени компиляции, либо исключение в этой точке, так как вы не можете использовать a String для Integer.