Java字节码:局部变量的类型?

JB2*_*JB2 10 java jvm bytecode

根据这篇文章http://slurp.doc.ic.ac.uk/pubs/observing/linking.html#assignment:

由于Java代码和字节码之间的信息不同(字节码不包含局部变量的类型),验证者不需要检查子类型以分配局部变量或参数.

我的问题:为什么字节码不包含局部变量的类型信息,而它确实包含参数和返回值的类型信息?

Ant*_*ony 6

首先,有几种不同的类型概念.有编译时类型,包括泛型.但是,编译时之后不存在泛型.

存在验证推断的变量静态类型,可以是int,float,long,double,returnaddress或对象引用.另外,对象引用以上限键入,因此所有引用都是java/lang/String例如子类型.字段还可以包含以下短类型之一:byte,short,char或boolean.出于执行目的,这些处理与int相同,但具有不同的存储.

最后,有运行时类型,它与验证的静态类型相同,但在对象引用的情况下,表示被引用的实例的实际类型.请注意,由于验证程序延迟,在某些情况下,运行时类型实际上可能不是验证类型的子类型.例如,声明类型的变量Comparable实际上可以保存Hotspot中的任何对象,因为VM在验证时不检查接口.

除非通过反射和调试的可选属性,否则不会保留编译时间信息.这是因为没有理由保留它.

局部变量没有明确的类型信息(除了新的StackMapTable属性,但这是技术性的).相反,当加载类时,字节码验证器通过运行静态数据流分析来推断每个值的类型.这样做的目的不是为了捕获编译时类型检查之类的错误,因为假设字节码在编译时已经经过了这样的检查.

相反,验证的目的是确保指令对VM本身没有危险.例如,它需要确保您没有采用整数并将其作为对象引用进行插入,因为这可能导致任意内存访问和黑客入侵VM.

因此,虽然字节码值没有显式类型信息,但它们确实具有隐式类型,这是静态类型推断的结果.这个细节根据每个VM的内部实现细节而有所不同,尽管它们应该遵循JVM标准.但是你只需要担心手写字节码.

字段具有显式类型,因为VM需要知道其中存储了哪种类型的数据.方法参数和返回类型在所谓的方法描述符中编码,也用于类型检查.它们不可能自动推断,因为这些值可以来自或去任何地方,而类型检查是按类进行的.

PS我在谈论验证类型时遗漏了一些细节.对象类型还会跟踪它们是否已初始化,以及在未初始化时创建它们的指令.地址类型跟踪创建它们的jsr的目标.