Вопрос

В каких обстоятельствах CASSCACTEXCECTION произойдет в коде ниже:

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList(1, 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

У нас был аналогичный случай в производственной среде (плохой практике, я знаю), и клиент предоставил журнал с классовом CASSEXCECTION на линии с комментарием, но я не могу его воспроизвести. есть идеи?

Я знаю, что JVM создает итератор на заднем плане при использовании Foreach, но он может создать необработанный итератор в некоторых случаях и параметризованный в других случаях?

Обновлять:Я также посмотрел на генерируемый байткод и в Windows, используя JDK 1.6.0_21-B07 NO контрольная передача сделан. Интересный :)

Вот главный метод:

Общественная статическая пустота Main (Java.lang.string []); Код: 0: invoxetatic # 34; // Метод getObjects :() ljava / util / list; 3: ASTORE_1 4: ALOAD_1 5: InvokeInterface # 36, 1; // Interfacemethod Java / UTIL / LIST.ТРИЧЕНИЕ :() LJAVA / UTIL / ITERATOR; 10: ASTORE_3 11: GOTO 28 14: ALOAD_3 15: InvokeInterface # 42, 1; // Interfacemethod Java / Util / iTerator.next :() ljava / lang / объект; 20: ASTORE_2 21: GetStatic # 48; // поле Java / lang / system.out: ljava / io / printstream; 24: Aload_2 25: InvokeWirtual # 54; // метод java / io / printstream.println: (ljava / lang / ebject;) v 28: Aload_3 29: InvokeInterface # 60, 1; // Interfacemethod Java / Util / iTerator.hasnext :() Z 34: IFNE 14 37: return

Спасибо всем за ответы!

Обновление 2.: Я вводил в заблуждение с ECLIPSE IDE, который использует его собственный компилятор Так что на самом деле байт-код выше это, сгенерированное с использованием Compiler Eclipse. Отказ Смотреть здесь Как вручную скомпилировать код с Eclipse. В заключении Eclipse Compiler генерирует другой байт-код из компилятора Солнца в некоторых случаях, независимо от платформы, чехол, описанный здесь, являющийся одним.

Это было полезно?

Решение

Разве этот код не должен всегда бросать ClassCastException? Это делает для меня, используя Sun Java 6 компилятора и время выполнения (на Linux). Вы отличаете IntegerС Stringс. Созданный итератор будет Iterator<String>, но тогда он пытается получить доступ к первому элементу, который является Integer, И так не удается.

Это становится более понятнее, если вы измените свой массив так:

return Arrays.asList("one", 2, 3);

Теперь петля на самом деле работает для первого элемента, потому что первый элемент является String и мы видим вывод; тогда Iterator<String> Не удается во второй, потому что это не строка.

Ваш код работает, если вы просто используете универсальный List вместо конкретного:

List list = getObjects();
for (Object o : list) {
    System.out.println(o);
}

... или, конечно, если вы используете List<Integer>, так как содержимое Integerс. Что вы делаете сейчас, вызывают предупреждение компилятора - Note: Generics.java uses unchecked or unsafe operations.- и по хорошей причине.

Эта модификация также работает:

for (Object o : (List)list)

... предположительно потому, что в этот момент вы имеете дело с Iterator, а не а Iterator<String>.

Божо сказал, что он не видит эту ошибку в Windows XP (не упомянул, какой компилятор и время выполнения, но я предполагаю, что вы думаете, что вы не видите его (или не надежно), так что есть некоторые Чувствительность реализации здесь, но нижняя строка: не используйте List<String> взаимодействовать с List из Integerс. :-)

Вот файл, который я составлен:

import java.util.Arrays;
import java.util.List;

public class Generics {

    static List getObjects() {
        return Arrays.asList("one", 2, 3);
    }

    public static void main(String[] args) {
        List<String> list = getObjects();
        for (Object o : list) { // ClassCastException?
            System.out.println(o);
        }
    }
}

Вот компиляция:

TJC @ FORGE: ~ / TEMP $ JAVAC Generics.java Примечание: Generics.java использует незаменимые или небезопасные операции. Примечание: перекомпилируйте с -xlint: не проверяют детали.

Вот беги:

TJC @ FORGE: ~ / TEMP $ Java Generics Одним из исключений в потоке «Главная» java.lang.classcastexception: java.lang.integer нельзя бросить на java.lang.string по сравнению с Enterics.

Линия 12 for утверждение. Обратите внимание, что он выводил первый элемент, потому что я изменил это на String. Отказ Это не выводило других. (И до того, как я сделал это изменение, это не удалось немедленно.)

Вот компилятор, который я использую:

TJC @ FORGE: ~ / TEMP $, javac / usr / bin / javac tjc @ forge: ~ / temp $ ll / usr / bin / javac lrwxrwxrwx 1 root 23 2010-09-30 16:37 / usr / bin / javac -> / etc / albolativaties / Javac * TJC @ FORGE: ~ / TEMP $ LL / etc / albileaties / javac lrwxrwxrwx 1 root 33 2010-09-30 16:37 / etc / albileaties / javac -> / usr / lib / lib / lib / javac JVM / Java-6-Sun / Bin / Javac *

Вот разборка, которая показывает checkcast:

TJC @ FORGE: ~ / TEMP $ JAVAP -C Generics, составленные из «Generics.java» общественных общего класса, расширяют Java.lang.Object {общедоступные универсальные (); Код: 0: ALOD_0 1: invoxial # 1; // Метод java / lang / объект "." :() v 4: возврат статической java.util.list getObjects (); Код: 0: iconst_3 1: Anewarray # 2; // Класс Java / IO / Serializable 4: DUP 5: iconst_0 6: LDC # 3; // String One 8: Aastore 9: DUP 10: iconst_1 11: iconst_2 12: invoxetatic # 4; // метод java / lang / integer.valueof: (i) ljava / lang / integer; 15: ASASTORE 16: DUP 17: iconst_2 18: iconst_3 19: invoxetatic # 4; // метод java / lang / integer.valueof: (i) ljava / lang / integer; 22: AASTORE 23: Invoxetatic # 5; // Метод java / util / actrays.aslist: ([ljava / lang / ebject;) ljava / util / list; 26: Areturn Public Static Void Main (Java.lang.string []); Код: 0: invoxetatic # 6; // Метод getObjects :() ljava / util / list; 3: ASTORE_1 4: ALOAD_1 5: InvokeInterface # 7, 1; // Interfacemethod Java / UTIL / LIST.ТРИЧЕНИЕ :() LJAVA / UTIL / ITERATOR; 10: ASTORE_2 11: ALOOD_2 12: InvokeInterface № 8, 1; // Interfacemethod Java / UTIL / ITERATOR.HASNEXT :() Z 17: IFEQ 40 20: ALOAD_2 21: InvokeInterface # 9, 1; // Interfacemethod Java / Util / iTerator.next :() ljava / lang / объект; 26: Checkcast # 10; // Класс Java / Lang / String 29: ASTORE_3 30: GetStatic # 11; // поле Java / lang / system.out: ljava / io / printstream; 33: Aload_3 34: Invokewirtual # 12; // метод java / io / printstream.println: (ljava / lang / объект;) v 37: goto 11 40: return}

Опять же, внизу должна быть: не используйте List<String> взаимодействовать с List который содержит вещи, которые не являются Stringс. :-)

Другие советы

Я тоже не могу его воспроизвести, но я обнаружил следующие ошибки, которые должны быть исправлены:

  • делать getObjects() возврат List<Integer>, а не сырой тип
  • Не ожидайте List<String>, но а List<Integer> вместо
  • При итерации, петли for (Integer o : list)

Проблема это метод static List getObjects() { Возвращает общий (не параметризованный) List. Отказ И вы назначаете это List<String>. Отказ Эта линия должна дать компилятору предупреждение, и это должно было сообщить проблему.

Эта часть :

List<String> list = getObjects();
for (Object o : list) { // ClassCastException?
    System.out.println(o);
}

Будет упрощен как

List<String> list = getObjects();
for (Iterator<String> iterator = list.iterator(); iterator.hasNext();) {
    Object o = iterator.next();
    System.out.println(o);
}

Но реализация итератора попытается отбрасывать при звонке next() Метод Содержание Отправить по Iterator в String.

Вот почему у вас есть CCE.

Решения:

Либо используйте дженерики везде или не используйте их, но это действительно важно, чтобы быть последовательным. Если вы вернули List<Integer> или а List<? super Integer> Вы бы видели эту проблему в момент компиляции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top