解析调用
所有方法调用的目标方法在Class
文件里边都是一个常量池中的符号引用。
在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用,
这种解析能成立的前提是:方法在程序真正运行之前就有一个可确定的调用
版本,并且这个方法的调用版本在运行期是不改变的。这类方法的调用被称为
解析(Resolution
)。
解析的方法
在Java语言
中符合“编译期可知,运行期不可变”这个要求的方法,主要有静态方法和
私有方法两大类,前者与类型直接关联,后者在外部不可被访问,这两种方法各自的
特点决定了它们都不可能通过继承或其他的方式重写出其他版本,因此适合在类加载
阶段进行解析。
调用方法的指令
调用不同的方法需要使用不同的指令。Java
虚拟机支持一下指令
invokestatic
:用于调用静态方法invokespecial
:用于调用实例构造器<init>()
方法、私有方法和父类中的方法invokevirtual
:用于调用所有虚方法invokeinterface
:用于调用接口方法,会在运行时再确定一个实现该接口的对象。invokedynamic
:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法。
非虚方法 & 虚方法
只要被invokestatic
和invokespecial
指令调用的方法,都可以在解析阶段中确定唯一的调用版本,
Java
语言里符合这个条件的方法共有静态方法、私有方法、实例构造器、父类方法4种。再加上被
final
修饰的方法(尽管它使用invokevirtual
指令调用),这5中方法调用会在类加载的时候就可以
把符号引用解析为该方法的直接引用。这些方法统称为“非虚方法”(Non-Virtual Method
)。
与之相反,其他的方法就被称为“虚方法”(Virtual Method
)。