Коллекции Java ArrayList, исключение приведения LinkedList - PullRequest
0 голосов
/ 23 октября 2018

Я нашел странный случай, который пока не могу объяснить.

 public static void main(String[] args) {
    LinkedList<Integer> a = new LinkedList<>();
    a.add(2);
    a.add(3);
    a.add(4);

    for (ArrayList ax : getBatches(a)){
        System.out.println(ax);
    }

}

private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
        return new ArrayList(Arrays.asList(optionIds));
}

Результат выполнения:

Исключение в потоке "main" java.lang.ClassCastException: java.util.LinkedList нельзя привести к java.util.ArrayList

Исключение возникает в цикле for.

Вопросы: как?Как метод с возвращаемым типом ArrayList > может вернуть LinkedList?

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

getBatches() возвращает ArrayList с универсальным типом ArrayList<Integer>.Тип возврата Arrays.asList() - это интерфейс List.Чтобы перейти от List к ArrayList, он выполняет неявное приведение.Проблема в том, что вы не можете напрямую преобразовать ArrayList в LinkedList.

Это относительно просто исправить.Вместо того, чтобы повторять ArrayList s, повторяйте List seg for(List l: getBatches(a).Тогда просто сделайте getBatches() return ArrayList<List<Integer>>

В общем, вы захотите использовать как можно более абстрактную вещь.Если вам не нужны детали реализации ArrayList, просто назовите его List.

0 голосов
/ 23 октября 2018

Это результат использования необработанного типа .

Вызовом new ArrayList(...) без указания общего параметра T из ArrayList<T> вы используете необработанный тип ArrayList.

В приведенных выше связанных документах сказано:

Но если вы назначите необработанный тип параметризованному типу, вы получите предупреждение:

Eclipseпоказывает следующее предупреждение, относящееся к new ArrayList(Arrays.asList(optionIds));:

Безопасность типов: выражение типа ArrayList нуждается в непроверенном преобразовании для соответствия ArrayList<ArrayList<Integer>>

Таким образом, оно не 't приводит к ошибке времени компиляции, которая возвращает необработанный типизированный ArrayList как ArrayList<ArrayList<Integer>>.

Результат getBatches(a) имеет тип ArrayList<ArrayList<Integer>>.Элементы этого типизированного списка имеют тип ArrayList<Integer>.Присвоение им ax с использованием необработанного типа ArrayList также не является ошибкой во время компиляции.

Для обратной совместимости допускается присвоение параметризованного типа его необработанному типу:

Но во время выполнения, когда дело доходит до приведения элемента от getBatches(a) до ArrayList, игнорирование предупреждения приводит к ClassCastException, поскольку тип времени выполнения LinkedList не может быть приведен к ArrayList (в настоящее время уже со стертыми родовыми типами).

0 голосов
/ 23 октября 2018

Ваш метод возвращает необработанный ArrayList, поэтому компилятор это позволяет.Однако во время выполнения делается попытка привести LinkedList (экземпляр, который вы передали методу getBatches) к ArrayList, что приводит к ClassCastException.

Если вы изменили свой методto:

private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
    return new ArrayList<>(Arrays.asList(optionIds));
}

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

Чтобы избежать ошибок компиляции и времени выполнения, вам необходимо преобразовать List, переданный в ваш метод, в ArrayList:

private static ArrayList<ArrayList<Integer>> getBatches(List<Integer> optionIds) {
    return new ArrayList<>(Arrays.asList(new ArrayList<>(optionIds)));
}

. Это вернет ArrayList, чей единственный элемент - ArrayList, содержащий те же элементы, что и List, переданный методу.

...