zzr*_*zrv 11 java generics casting
我正在使用java 8.
我最近遇到过这个:
public class Test {
public static void main(String[] args) {
String ss = "" + (Test.<Integer>abc(2));
System.out.println(Test.<Integer>abc(2));
}
public static <T> T abc(T a) {
String s = "adsa";
return (T) s;
}
}
Run Code Online (Sandbox Code Playgroud)
这不会抛出java.lang.ClassCastException.这是为什么?
我一直在思考+和System.out.println打电话toString.但是当我尝试这样做时,它会按预期抛出异常.
String sss = (Test.<Integer>abc(2)).toString();
Run Code Online (Sandbox Code Playgroud)
Ted*_*opp 12
它不会抛出ClassCastException因为所有泛型类型信息都从编译代码中剥离(称为类型擦除的过程).基本上,任何类型参数都替换为Object.这就是第一个版本有效的原因.这也是代码编译的原因.如果您要求编译器使用该-Xlint:unchecked标志警告未经检查或不安全的操作,您将在return语句中收到有关未经检查的强制转换的警告abc().
有了这个声明:
String sss = (Test.<Integer>abc(2)).toString();
Run Code Online (Sandbox Code Playgroud)
这个故事有点不同.当类型参数T被替换时Object,调用代码被转换为显式地将结果转换为的字节代码Integer.就好像代码是用带签名的方法编写的,static Object abc(Object)并且语句写成:
String sss = ((Integer) Test.abc(Integer.valueOf(2))).toString();
Run Code Online (Sandbox Code Playgroud)
也就是说,abc()由于类型擦除,内部的强制转换不仅会消失,编译器会在调用代码中插入新的强制转换.此转换生成一个ClassCastException运行时,因为返回的对象abc()是a String,而不是Integer.
请注意该声明
String ss = "" + (Test.<Integer>abc(2));
Run Code Online (Sandbox Code Playgroud)
不需要强制转换,因为编译器只是将返回的对象反馈到对象abc()的字符串连接操作中.(有关如何完成此操作的详细信息因Java编译器而异,但它是对StringBuilderappend方法的调用,或者从Java 9开始,调用StringConcatFactory由此创建的方法.)此处的详细信息无关紧要; 关键是编译器足够聪明,可以识别不需要强制转换.
泛型在运行时消失,所以一个强制转换T实际上只是一个强制转换Object(编译器实际上只是摆脱它),因此没有类强制转换异常.
abc只是一个获取对象并返回一个对象的方法.StringBuilder.append(Object)是从字节码中可以看到的被调用的方法:
...
16: invokestatic #7 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
19: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder;
...
Run Code Online (Sandbox Code Playgroud)
当你这样做
String sss = (Test.<Integer>abc(2)).toString();
Run Code Online (Sandbox Code Playgroud)
然后是字节码
...
4: invokestatic #3 // Method abc:(Ljava/lang/Object;)Ljava/lang/Object;
7: checkcast #4 // class java/lang/Integer
10: invokevirtual #5 // Method java/lang/Integer.toString:()Ljava/lang/String;
...
Run Code Online (Sandbox Code Playgroud)
您的代码在以前不存在的checkcast操作中失败.
| 归档时间: |
|
| 查看次数: |
822 次 |
| 最近记录: |