为什么println
打印&#34; tom&#34;并且在转换为List<Integer>
后没有显示任何运行时异常,而在转换为List<String>
后无法打印值1?
import java.util.Arrays;
import java.util.List;
public class Main {
public static void main(String args[]) {
List list = Arrays.asList(1, "tom");
System.out.println(((List<Integer>) list).get(1));
// "tom"
System.out.println(((List<String>) list).get(0));
// ClassCastException: Integer cannot be cast to String
}
}
答案 0 :(得分:34)
println
的第一次呼叫被静态分派到PrintStream.println(Object)
,第二次呼叫被分派到PrintStream.println(String)
。因此,对于第二次调用,编译器将隐式强制转换为String
,然后在运行时失败并显示ClassCastException
。
答案 1 :(得分:3)
这里的问题是java编译器在编译时选择方法,而不是运行时。
在编译时,它将选择方法PrintStream.print(String)
,而不是PrintStream.print(int)
或PrintStream.print(Object)
,两者都会成功。
答案 2 :(得分:0)
Integer i = new Integer(101);
String s = new String(i); // undefined and Invalid
StringBuffer sb = new StringBuffer(i); // defined and Valid
String s2 = "tom";
Integer i2 = new Integer(s2); //defined and valid
因此,当您将非泛型列表分配给泛型列表时,它会被分配,但是当您打印它时,它会检查类型安全性或定义构造函数以进行强制转换,如果有有效和已定义的构造函数则打印出来,否则显示类强制转换异常由于缺少用于投射的未定义构造函数,因此无法投放该类。
如果我错了,请用正确的逻辑帮助我......
答案 3 :(得分:0)
使用泛型可以避免这类问题,这是使用泛型的主要动机。
这是您的代码的实际流程,从您的第二个println(
)角度来看:
您的代码声明ArrayList
类型为Object
;
它向Integer
添加String
和ArrayList
。
它将您的列表转换为String
列表。您的列表标记为仅限String
。
Java泛型只是一个编译时功能,因此您的列表可以接受没有任何问题的String
和Integer
元素。与编译器不同,对象本身对它所包含的类型一无所知。
它试图检索您的已转换列表的第一个元素,该元素应该是String
并隐式地将其强制转换为String
。
从println(String x)
班级拨打PrintStream
。
但是第一个元素实际上不是String
而是Integer
。
您无法将Integer
转换为String
。
阅读Generics in Java动机部分示例。