为什么可以取回一个“的对象”;“类型不正确”;从Java中的参数化列表中?
下面是一段代码片段:为什么可以取回一个“的对象”;“类型不正确”;从Java中的参数化列表中?,java,generics,raw-types,parameterized-types,Java,Generics,Raw Types,Parameterized Types,下面是一段代码片段: 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
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");
}
}
import java.util.*;
课堂测试
{
公共静态void main(字符串[]args)
{
列表=新的ArrayList();
地址列表(列表);
整数i=list.get(0);//#1在运行时失败
字符串s=list.get(0);//#2在编译时失败
list.get(0);/#3可以正常工作
System.out.println(list.get(0));//#4工作正常,打印“字符串”
}
静态无效添加列表(列表){
列表。添加(“字符串”);
}
}
我理解为什么可以在参数化列表中插入String类的对象
似乎我理解了为什么标有#1
和#2
的代码会失败
但是为什么
#3
和#4
起作用呢?据我所知,编译器会在类型擦除后添加适当的强制转换,因此当我调用list.get(0)
时,此方法应返回以前强制转换为整数的对象。那么,为什么在运行时在第3和第4个位置没有发生ClassCastException呢?强制类型转换应用于get
的返回类型,而不是引入污染的add
。否则,您将在此时得到编译时错误或异常,因为您无法将字符串
强制转换为整数
,由于忽略了get(int)
返回的对象,所以#3可以工作。将返回存储在位置0
的内容,但由于没有强制转换,因此不会发生错误
#4工作正常的原因是相同的:由
get(0)
生成的对象被视为java.lang.object
中的println
子类,因为调用了toString
。由于toString()
可用于所有Java对象,因此调用将在没有错误的情况下完成。首先,您可以向列表添加字符串的原因。在方法中
static void addToList(List list){
您使用原始类型。原始类型的存在纯粹是为了与旧的Java版本兼容,不应在新代码中使用。在addToList
方法中,Java编译器不知道list
应该只包含整数,因此当向其添加字符串时,它不会抱怨
至于你们两人的不同行为Integer i=list.get(0)
在编译时不会失败,因为Java认为list
只包含Integer
s。只有在运行时,list
的第一个元素不是整数,因此您得到了一个ClassCastException
String s=list.get(0)
在编译时失败,因为Java编译器假定list
仅包含整数,因此它假定您尝试将整数分配给字符串引用
Justlist.get(0)
不存储方法调用的结果。因此,无论是在编译时还是在运行时,都没有任何失败的原因
最后,System.out.println(list.get(0))
工作,因为System.out
是一个PrintStream
,并且有一个println(Object)
方法,可以用整型
参数调用该方法。4:正在调用重载的System.out.println(Object),因为整数如果您查看ArrayList#get
方法。这是:
public E get(int index) {
//body
}
但在运行时,它实际上是:
public Object get(int index) {
//body
}
所以当你做整数i=list.get(0)代码>
编译器将其转换为:
Integer i = (Integer)list.get(0);
现在在运行时,list.get(0)
返回一个对象
类型(实际上是字符串
)。它现在尝试转换String=>Integer
,但失败了
3.
因为它只是:
list.get(0)
编译器不会向任何内容添加类型转换。所以它只是,list.get(0)
4.
list.get(0)
返回一个对象
类型。所以调用PrintStream的publicvidprintln(objectx)
方法
记住被调用而不是被调用。抱歉,但是你似乎误解了这个问题。(顺便说一句,请随意修改你的答案,我将收回我的否决票。或者,如果你觉得其他答案足够,你可以删除它。)你的意思是,只有当我分配get(0)的结果时,才能转换为整数到某个变量?@fromSPb是的。除非将值指定给需要强制转换的对象,否则不会强制转换为整数。+1。JLS实际上没有规定“铸造”本身是发生的;相反,它指定如果实例的运行时类型与目标类型不匹配,则赋值转换()和方法调用转换()可以引发ClassCastException。OP的#3和#4不会触发这些规则中的任何一条,因此不存在ClassCastException。@dasblinkenlight感谢您的解释!因为并非所有的列表
使用都已参数化:)
System.out.println(list.get(0));