#fecf0f
此代码给出了运行时错误:
public class Box<T> {
private T t;
public Box(T t){
this.t = t;
}
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> b = new Box(new String("may be"));
System.out.println(b.get()); // successfully print out "may be"
System.out.println(b.get().getClass()); // error
}
}
exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
没有触发运行时错误?更确切地说:为什么编译器将b.get()
指令插入 second checkcast
的字节码 (导致例外)?
答案 0 :(得分:2)
请注意:
get()
的结果用于println(Object)
:换句话说:接收方需要一个对象,并且“条件”将始终为真。作为背景,可以查看Java语言规范,第5.52章:
演员表是经过检验的演员。
此类演员需要运行时有效性检查。如果运行时的值为null,则允许转换。否则,令R为运行时引用值引用的对象的类,并且让T为转换运算符中指定的类型的擦除(第4.6节)。强制转换必须在运行时通过§5.5.3中的算法检查类R是否与类型T兼容。
分别为第5.53章Checked Casts at Run Time。
答案 1 :(得分:2)
此变量声明不一致。
Box<Integer> b = new Box(new String("may be")); :
实例化对象是原始对象,因此编译器会发出警告,但允许将原始类型分配给通用变量:Box<Integer>
。
b.get()
不会因为您没有将结果分配给变量而失败。
因此,编译器不需要将其转换为任何内容。
试试:
Integer value = b.get();
它将编译正常,但您将在运行时获得相同的异常
JVM将尝试将值转换为Integer
:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
当您调用时:
System.out.println(b.get().getClass()); // error
事情已接近。
为什么此处需要Integer
课程?
在编译时,b
被声明为Box<Integer> b
因此,编译器知道b
参数化为Integer
类型
所以在编译之后是,擦除了泛型,但编译器根据声明的代码添加了一些强制转换。
这就是这种情况。
您对使用getClass()
参数化的变量调用Integer
。
但Class
是一个通用类:Class<T>
。因此,编译器添加了对Integer
的强制转换以符合Class<Integer>
。
当然,通过将泛型用于变量声明和实例化:
Box<Integer> b = new Box<>(new String("may be"));
这种不一致是不可能的,因为编译器现在停止了你。
答案 2 :(得分:1)
除了这里的答案之外,字节指令checkcast
在类型为Object
的typechecks上被调用。例如
public static void main(String[] args) {
Box<Integer> b = new Box(new String("may be"));
doStuff(b.get()); // no checkcast needed - works fine
doIntegerStuff(b.get()); // run-time error with checkcast
doStringStuff(b.get()); // compile error
}
public static void doStuff(Object object){}
public static void doStringStuff(String integer){}
public static void doIntegerStuff(Integer integer){}
答案 3 :(得分:-1)
代码行Box<Integer> b = new Box(new String("may be"));
在创建新的Box
对象时,缺少类型Info,并假定为默认的Object
类。
Box<String> b = new Box<>(new String());
这是正确的方法
--------添加了--------
在Object
类的方法getClass()
中返回运行时Class
对象。并且在返回时,您的代码Box<Integer>
会使getClass()
方法返回Class<Integer>
而不是Class<String>
。
你给了new B(new String());
的原始类型,所以编译器传递了语法,但在调用getClass()
时,它将内部对象String
强制转换为Integer
并抛出RuntimeException