动态链接:class文件中,一个方法调用其他方法,需要将方法的符号引用转化为内存地址的直接引用。类中调用父类方法,运行时执行子类方法(多态)
方法返回:把当前栈帧出栈。正常完成出口 / 异常完成出口
本地方法栈
直接操作硬件,C++方法
方法执行
先由Java编译器编译为Java字节码,再由Java解释器逐条解释,或对热点代码由JIT编译器编译运行
热点代码:被多次调用的方法;被多次执行的循环体
方法调用计数器:先检查是否存在已编译版本,否则方法调用次数加1,超过阈值则启动编译
加载存储指令
将一个局部变量表加载到操作数栈:load系列
将一个数值从操作数栈加载到局部变量表:store系列
将一个常量加载到操作数栈:const系列、push系列、ldc系列
JIT运行方式
Server模式,Client模式
优化
公共子表达式消除
方法内联
逃逸分析(存在逃逸则无法优化)
栈上内存分配
标量替换
同步锁消除
方法调用
常见方法调用类型
私有方法:与类绑定,编译时确定
构造方法:与类绑定,编译时确定
静态方法:与类绑定,编译时确定
成员方法:不与类绑定,运行时确定
接口方法:不与类绑定,运行时确定
编译看左边,运行看右边
重载与重写
重写(overwrite):也叫方法覆盖,继承或实现关系下,子类和父类方法描述符(参数和返回值)一致,方法名称一致
重载(overloading):在同一个类中,方法名称一致,方法参数(类型和顺序)不一致,不关心返回值
可理解为运行时重新加载,即编译时按左边类,运行时才加载右边真正类型
静态绑定和动态绑定
通过类名、方法名、方法描述符识别方法
属性看左,方法看右
通过父类引用访问子类的属性,需要强制转型
方法调用指令
invokevirtual:调用非静态非私有方法(多态)
invokeinterface:调用接口方法(多态)
invokespecial:调用非静态私有方法、构造方法
invokestatic:调用静态方法
invokedynamic
方法调用过程
静态绑定方法:直接在运行时常量池找到引用
动态绑定方法:根据父类方法表确定要查找的方法索引(编译看左),从子类方法表中开始,找不到再去父方法表找
虚分配
Father father = new Son();
father指针指向son对象
根据本地变量表,找调用该虚方法的对象
取出对象头中的类型指针,找到Class对象
找到Class对象后,找到对应的虚方法表
找到对应的方法,进行方法调用
如果找不到,则去父类对象查找,最终找不到则报错
public class DynamicCall01 { public static void main(String[] args) { Father father = new Son(); // 多态,发生方法重载 father.f1(); // 打印结果: Son-f1() char c = 'a'; father.f1(c); // 打印结果: father-f1() para-int 97 } } // 被调用的父类 class Father { public void f1() { System.out.println("father-f1()"); } public void f1(int i) { System.out.println("father-f1() para-int " + i); } } // 被调用的子类 class Son extends Father { public void f1() { // 覆盖父类的方法 System.out.println("Son-f1()"); } public void f1(char c) { System.out.println("Son-s1() para-char " + c); } }