分配给泛型类型运行时getClss()方法的Java原始类型值错误 为什么b.get()没有触发运行时错误 为什么只有在尝试获取类变量的类时才会发生运行时错误
更准确地说:为什么编译器只在第二个分配给泛型类型运行时getClss()方法的Java原始类型值错误 为什么b.get()没有触发运行时错误 为什么只有在尝试获取类变量的类时才会发生运行时错误,java,generics,casting,runtime,Java,Generics,Casting,Runtime,更准确地说:为什么编译器只在第二个get()(导致异常)的字节码中插入checkcast指令 在代码行中框b=新框(新字符串(“可能”) 创建新的框时对象缺少类型信息,并假定为默认的对象类 Box b=newbox(newstring())这是正确的方法 --------增加-------- 在Objectclass的方法getClass()中,返回运行时class对象。当返回时,代码框生成getClass()方法以返回Class而不是Class 您使用new B(new String())创建
get()
(导致异常)的字节码中插入checkcast
指令 在代码行中框b=新框(新字符串(“可能”)代码>
创建新的框时
对象缺少类型信息,并假定为默认的对象
类
Box b=newbox(newstring())代码>这是正确的方法
--------增加--------
在Object
class的方法getClass()
中,返回运行时class
对象。当返回时,代码框
生成getClass()
方法以返回Class
而不是Class
您使用new B(new String())创建了原始类型代码>因此编译器传递了语法,但在调用getClass()
时,它将内部对象String
转换为Integer
,并抛出RuntimeException,请注意:
- 在第一种情况下,
get()
的结果用于println(Object)
:换句话说,接收方需要一个Object,并且“condition”总是true
- 在第二种情况下,随后将对返回的对象调用方法。现在,如果返回的类型是预期的类型,那么它可以产生巨大的差异。因此,编译器正在添加此检查,以确保以下方法调用是可靠的
作为背景,我们可以了解Java语言规范,第5.52章:
该演员阵容为选中演员阵容
这样的强制转换需要运行时有效性检查。如果运行时的值为null,则允许强制转换。否则,设R为运行时引用值引用的对象类,T为强制转换运算符中指定类型的擦除(§4.6)。强制转换必须在运行时通过§5.5.3中的算法检查类别R的赋值是否与类型T兼容
分别在第5.53章。此变量声明不一致
exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
它可以很好地编译,但在运行时会得到与
JVM将尝试将值强制转换为Integer
:
Integer value = b.get();
当您调用:
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
一切都很接近。
为什么这里需要整数类?
在编译时,b
被声明为框b
因此编译器知道b
是用Integer
类型参数化的。
因此,编译后是的,泛型将被删除,但编译器会根据声明的代码添加一些强制转换。
这里就是这样。
对使用Integer
参数化的变量调用getClass()
但是Class
是一个泛型类:Class
因此编译器添加了对Integer
的强制转换,以符合Class
当然,通过对变量声明和实例化使用泛型:
System.out.println(b.get().getClass()); // error
Box b=新框(新字符串(“可能”);
这种不一致性是不可能的,因为编译器现在阻止您。除了这里的答案之外,字节指令checkcast
在类型检查时被调用,而类型检查不是对象的具体类型。比如说
Box<Integer> b = new Box<>(new String("may be"));
publicstaticvoidmain(字符串[]args){
框b=新框(新字符串(“可能”));
doStuff(b.get());//不需要检查强制转换-工作正常
doIntegerStuff(b.get());//checkcast的运行时错误
doStringStuff(b.get());//编译错误
}
公共静态void doStuff(对象){}
公共静态void doStringStuff(字符串整数){}
公共静态void doIntegerStuff(整数){}
我没有把这个问题理解为“我如何解决这个问题?”而是“为什么原始类型会以这种特殊的方式中断?”我假设get
只会给你一个指向某个对象的指针,在你的示例中调用toString
,但是getClass
实际上会检查并解析该类型。您需要一个整数
,但对象是一个字符串
,因此getClass
在内部强制转换它并失败。@GhostCat更清楚了@鬼猫去吧。我一点也不介意。谢谢你的邀请improvement@GhostCat是,它在第二个get
中插入它,因为类型检查来自getClass
。第一行不会引发异常,因为所有对象类型都实现了toString
。您调用的任何试图解析类型的方法都将抛出异常。预期的返回类型为Class
,当类声明为
时,返回类将毫无意义,因此castwhy getClass()与get()不同,因为getClass()将在get()时执行强制转换不会施放,但只返回对象是什么?在本例中,尽管get()是根据声明返回一个整数,但它实际上返回了一个字符串而不会引起问题,而getClass()关心它返回的是什么类型?谢谢你的回答,我只是需要澄清一下。
System.out.println(b.get().getClass()); // error
Box<Integer> b = new Box<>(new String("may be"));
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){}