java 静态分派_Java的动态分派和静态分派的实现

Java 方法执行时的动态分派和静态分派是 Java 实现多态的本质

背景

Java 的动态分派和静态分派也是 Java 方法的执行原理。 Java 源代码的编译之后,方法之间的调用是使用符号引用来表示的。当字节码被 JVM 加载之后,符号引用才会被替换为对应方法在方法区的真实内存地址。那么在替换之前,由于 Java 的方法重写、重载,就导致符号引用对应的方法可能是一个虚方法,那么方法的真实实现在运行时就可能有多个。

所以在将符号引用替换为真实地址时,还需要做一件事情:那就是确定符号引用要替换的方法的版本。

运行时方法帧

与 C,C++ 一样,JVM 在运行时也会维护一个运行栈,用于方法的调用和返回。当调用一个方法时,会为方法在栈上分配一块内存区域作为方法的帧。方法调用帧又分为下面几个区域:

局部变量表

存储方法参数和方法体中的局部变量,其容量在编译期就已确定。容量的最小单位是 variable slot(变量槽)。

静态方法的局部变量数就是方法体中声明的变量数;实例方法的局部变量数会多一个,多出的一个就是我们平时在实例方法中访问的this。this 其实是编译器在编译时悄悄加到实例方法上的,而且是作为第一个参数。

操作数栈

JVM 的字节码指令执行机制是基于栈的,所以需要一个栈来存储字节码指令的操作数。

Android 的 VM 是基于寄存器的,所以没有操作栈区域。

Android VM 采用寄存器存储操作数有两个主要原因:1. 寄存器乃是 CPU 内部的高速内存, 读写寄存器是与 CPU 交互最快的方式。2. 智能手机多使用 ARM 架构的 CPU, ARM 架构的 CPU 有很多通用寄存器可使用。

动态链接

方法体中调用其他方法时,会把将要调用的方法在常量池中的符号引用,转化为将要其在方法区内存中的开始地址信息,并储存到动态链接中。

方法返回地址

一个方法执行完毕之后,线程需要值得回到哪里继续执行,方法返回地址就是存储这个信息的。返回地址一般就是当前方法的调用者的程序计数器的值(PC寄存器)。

正常完成出口: 方法正常返回时,如果有返回值,返回值会被压入调用方法的操作数栈中

异常完成出口: 当方法发生了异常,且在异常表中没有找到匹配的异常处理流程时,方法将不会有返回值

方法调用

方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法)

调用方法的指令

有以下字节码指令用于方法的调用:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在 C 语言中,没有直接支持静态多态和动态多态的语法特性。不过,可以通过一些技巧来实现类似的效果。 1. 静态多态(静态分派): 静态多态是指在编译时根据函数参数的类型来确定要调用的函数版本。在 C 语言中,可以使用函数指针来实现类似的效果。可以定义一个函数指针类型,然后根据不同的参数类型给函数指针赋不同的函数地址。通过调用函数指针来实现不同的行为。 示例代码: ```c #include <stdio.h> typedef void (*func_ptr)(int); // 定义函数指针类型 void func1(int x) { printf("Calling func1: %d\n", x); } void func2(int x) { printf("Calling func2: %d\n", x); } int main() { func_ptr ptr; ptr = func1; // 给函数指针赋值 ptr(10); // 调用函数指针,输出 "Calling func1: 10" ptr = func2; ptr(20); // 调用函数指针,输出 "Calling func2: 20" return 0; } ``` 2. 动态多态(动态分派): 动态多态是指在运行时根据对象的实际类型来确定要调用的函数版本。在 C 语言中,可以使用结构体和函数指针组合来实现类似的效果。定义一个结构体,包含不同类型的对象和对应的函数指针。通过运行时判断对象的实际类型,然后调用相应的函数指针,实现不同的行为。 示例代码: ```c #include <stdio.h> typedef struct { int type; void (*func_ptr)(void*); } Object; void func1(void* obj) { printf("Calling func1\n"); } void func2(void* obj) { printf("Calling func2\n"); } void process(Object* obj) { if (obj->type == 1) { obj->func_ptr(obj); } else if (obj->type == 2) { obj->func_ptr(obj); } } int main() { Object obj1 = {1, func1}; Object obj2 = {2, func2}; process(&obj1); // 输出 "Calling func1" process(&obj2); // 输出 "Calling func2" return 0; } ``` 这样就可以通过函数指针的方式实现静态多态和动态多态的效果。需要注意的是,在 C 语言中没有自动的类型检查和转换,所以需要手动进行类型判断和转换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值