文章目录
一、动态链接
注意:运行时常量池位于方法区中,在JDK1.7及之后版本的JVM已经将运行时常量池从方法区中移了出来,在Java堆中开辟了一块新的区域存放运行时常量池
- 常量池的作用:提供一些符号和常量,便于指令的识别;
- 在每一个栈帧内部中均包含一个指向运行时常量池(Constant Pool)或该栈帧所述方法的引用;包含这个引用的目的就是支持当前方法的代码能够实现动态连接,比如invokedynamic指令;
- 在Java源文件被编译成字节码文件时,所有的变量和方法都作为符号引用(Symbolic Reference)保存在class字节码文件的常量池中;比如:描述了一个方法调用了其他方法时,就是通过常量池中指向方法的符号引用来表示的,那么动态链接的作用就是将这些符号引用转换为调用方法的直接引用;
二、方法调用
1.引入库
在JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制有关
-
静态链接
当一个字节码文件被装载进JVM内部时,如果被调用的目的方法在编译期可知,且在运行期保持不变时,这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接; -
动态链接
如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行的时候将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接;对应的方法绑定机制为:早期绑定和晚期绑定;
-
早期绑定
早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时,即可将这个方法与所属的类型进行绑定,这样一来,由于明确了别调用的方法究竟是哪一个,因此也就可以使用静态链接的将符号引用转换为直接引用; -
晚期绑定
如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式被称之为晚期绑定;
随着高级语言的横空出世,类似于Java一样的基于面向对象的语言如今越来越多尽管这类编程语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持封装,集成和多态等面向对象特性,既然这一类的编程语言具备多态特性,那么自然也就具备早期绑定和晚期绑定两种绑定方式。
Java中任何一个普通的方法其实都具备虚函数的特征,它们相当于C++语言中的虚函数(C++中则需要使用关键字virtual来显式定义)。如果在Java程序中不希望某个方法拥有虚函数的特征时,则可以使用关键字final来标记这个方法。
三、虚方法和非虚方法
子类对象的多态性使用前提: 1. 类的继承关系(父类的声明);2. 方法的重写(子类的实现)
在实际中执行的是导入的第三方jar包
- 非虚方法
- 如果方法在编译期就确定了具体的调用版本,这个版本在运行的时候是不可变的,那么这样的方法就被称为非虚方法;
- 静态方法,私有方法,final方法,实例构造器(实例已经确定,this()表示本类的构造器,父类方法(super调用)都是非虚方法);
- 其他所有体现多态性的方法称为虚方法;
四、虚拟机中提供了以下几条方法调用指令
-
普通的调用指令
- invokestatic:调用静态方法,解析阶段确定唯一的方法版本;
- invokespecial:调用方法,私有及父类方法,解析阶段确定唯一的方法版本;
- invokevirtual调用所有的虚方法;
- invokeinterface:调用接口方法;
-
动态调用指令(Java7中新增)
- invokedynamic:动态解析出需要调用的方法,然后执行;
-
前四条指令固化在虚拟机的内部,方法的调用执行不可人为干预,而invokedynamic指令则支持由用户确定方法版本;
-
其中invokestatic指令和invokespecial指令调用的方法称为非虚方法;invokevirtual(final修饰的除外,JVM会把final方法调用也归为invokevirtual指令,但要注意final方法调用不是虚方法),invokeinterface指令调用的方法称为虚方法;
/**
* 解析调用中非虚方法、虚方法的测试
*/
class Father {
public Father(){
System.out.println("Father默认构造器");
}
public static void showStatic(String s){
System.out.println("Father show static&