Due to the differences in information between Java code and bytecode
(bytecode does not contain the types of local variables),the verifier
does not need to check subtypes for assignments to local variables,or
to parameters.
我的问题:为什么字节码不包含局部变量的类型信息,而确实包含参数和返回值的类型信息?
解决方法
有一个变量的验证推断的静态类型,可以是int,float,long,double,returnaddress或对象引用.对象引用另外键入上限,所以所有引用都是java / lang / String的子类型.字段可以另外具有一个短类型:byte,short,char或boolean.这些被视为与执行目的相同,但具有不同的存储空间.
最后,存在与验证的静态类型相同的运行时类型,但是在对象引用的情况下,表示被引用的实例的实际类型.请注意,由于验证器懒惰,有些情况下运行时类型可能实际上不是验证类型的子类型.例如,声明的Comparable类型的变量实际上可以在Hotspot中保存任何对象,因为VM在验证时不检查接口.
编译时间信息不会被保留,除非通过反射和调试的可选属性.这是因为没有理由保留.
局部变量没有明确的类型信息(除了新的StackMapTable属性,但这是一个技术性).相反,当加载类时,字节码验证器通过运行静态数据流分析来推断每个值的类型.这样做的目的是不要像编译时类型检查那样捕获错误,因为假设字节码在编译时已经经过了这样的检查.
相反,验证的目的是确保指令对VM本身并不危险.例如,它需要确保您没有采取整数并将其作为对象引用进行间隔,因为这可能会导致任意内存访问和黑客入侵.
所以虽然字节码值没有显式的类型信息,但是它们有一个隐式类型,它是静态类型推断的结果.这些细节根据每个虚拟机的内部实现细节而有所不同,尽管它们应遵循JVM标准.但是你只需要担心手写字节码.
字段具有显式类型,因为VM需要知道其中存储哪种类型的数据.方法参数和返回类型以所谓的方法描述符进行编码,也用于类型检查.它们不可能自动推断,因为这些值可以来自或去任何地方,而类型检查是按照每个类进行的.
附:在谈论验证类型时,我省略了一些细节.对象类型还跟踪它们是否已被初始化,以及哪些指令在未初始化时创建它们.地址类型跟踪创建它们的jsr的目标.