Ama*_*n J 4 java raw-types classcastexception java-8 unchecked-cast
执行下面的代码时,代码执行完美而没有任何错误,但对于类型的变量,方法List<Integer>的返回类型get()应该是Integer,但是在执行此代码时,当我调用x.get(0)一个字符串时返回,而这应该抛出一个例外.
public static void main(String[] args)
{
ArrayList xa = new ArrayList();
xa.addAll(Arrays.asList("ASDASD", "B"));
List<Integer> x = xa;
System.out.println(x.get(0));
}
Run Code Online (Sandbox Code Playgroud)
但是在执行下面的代码时,只需将返回对象的类检索添加到前一个代码块就会引发类强制转换异常.如果上面的代码完美执行,则以下内容也应该执行而没有任何异常:
public static void main(String[] args)
{
ArrayList xa = new ArrayList();
xa.addAll(Arrays.asList("ASDASD", "B"));
List<Integer> x = xa;
System.out.println(x.get(0).getClass());
}
Run Code Online (Sandbox Code Playgroud)
为什么java在获取对象的类类型时执行类型转换?
编译器必须在必要时在字节代码级别插入类型检查指令,因此在对表达式进行赋值时Object,例如Object o = x.get(0);或者System.out.println(x.get(0));可能不需要它,在表达式上调用方法x.get(0) 确实需要它.
原因在于二进制兼容性规则.简单地说,调用方法是由接收器类型继承还是显式声明是无关紧要的,表达式的形式类型x.get(0)是Integer你正在调用getClass()它的方法,因此,调用将被编码为方法的调用以接收器类getClass的签名命名.此方法已继承并且在编译时声明的事实不会被编译的类反映出来.() ? java.lang.Classjava.lang.Integerjava.lang.Objectfinal
因此从理论上讲,在运行时,可以删除该方法java.lang.Object并java.lang.Class getClass()添加新方法,java.lang.Integer而不会破坏与该特定代码的兼容性.虽然我们知道这种情况永远不会发生,但编译器只是遵循正式规则而不是将有关继承的假设注入代码中.
由于调用将被编译为调用目标java.lang.Integer,因此在调用指令之前必须进行类型转换,这将在堆污染方案中失败.
请注意,如果您将代码更改为
System.out.println(((Object)x.get(0)).getClass());
Run Code Online (Sandbox Code Playgroud)
你将明确假设该方法已被声明java.lang.Object.java.lang.Object所有这些代码所做的扩展都不会产生任何额外的字节代码指令,正在改变方法调用的接收器类型java.lang.Object,从而消除了对类型转换的需要.
还有就是从这里开始的规则一个有趣的偏差,编译器不编码调用作为调用上java.lang.Object的字节码水平,如果该方法是已知的一个final中声明的方法java.lang.Object.这可能是因为这些特定方法是在JLS中指定的,并且以这种形式对它们进行编码允许JVM快速识别这些特殊方法.但是checkcast指令和invokevirtual指令的组合仍然表现出相同的兼容行为.
| 归档时间: |
|
| 查看次数: |
184 次 |
| 最近记录: |