Разве этот код не должен всегда бросать 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 (не упомянул, какой компилятор и среда выполнения, но я предполагаю, что Sun)и вы говорите, что не видите его (или не надежно), поэтому ясно, что здесь есть некоторая чувствительность реализации, но суть в следующем: не используйте List<String>
для взаимодействия с List
из Integer
s.: -)
Вот файл, который я компилирую:
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
Note: Generics.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
Вот прогон:
tjc@forge:~/temp$ java Generics
one
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at Generics.main(Generics.java:12)
Строка 12 - это оператор for
.Обратите внимание, что он вывел первый элемент, потому что я изменил его на String
.Это не выводило других.(И до того, как я сделал это изменение, оно сразу же вышло из строя.)
Вот компилятор, который я использую:
tjc@forge:~/temp$ which javac
/usr/bin/javac
tjc@forge:~/temp$ ll /usr/bin/javac
lrwxrwxrwx 1 root root 23 2010-09-30 16:37 /usr/bin/javac -> /etc/alternatives/javac*
tjc@forge:~/temp$ ll /etc/alternatives/javac
lrwxrwxrwx 1 root root 33 2010-09-30 16:37 /etc/alternatives/javac -> /usr/lib/jvm/java-6-sun/bin/javac*
Вот разборка, которая показывает checkcast
:
tjc@forge:~/temp$ javap -c Generics
Compiled from "Generics.java"
public class Generics extends java.lang.Object{
public Generics();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."":()V
4: return
static java.util.List getObjects();
Code:
0: iconst_3
1: anewarray #2; //class java/io/Serializable
4: dup
5: iconst_0
6: ldc #3; //String one
8: aastore
9: dup
10: iconst_1
11: iconst_2
12: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
15: aastore
16: dup
17: iconst_2
18: iconst_3
19: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
22: aastore
23: invokestatic #5; //Method java/util/Arrays.asList:([Ljava/lang/Object;)Ljava/util/List;
26: areturn
public static void main(java.lang.String[]);
Code:
0: invokestatic #6; //Method getObjects:()Ljava/util/List;
3: astore_1
4: aload_1
5: invokeinterface #7, 1; //InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
10: astore_2
11: aload_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/Object;
26: checkcast #10; //class java/lang/String
29: astore_3
30: getstatic #11; //Field java/lang/System.out:Ljava/io/PrintStream;
33: aload_3
34: invokevirtual #12; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V
37: goto 11
40: return
}
Опять же, нижняя строка должна быть такой: Не используйте List<String>
для взаимодействия с List
, который содержит вещи, которые не String
с.: -)