🌈hello,你好鸭,我是Ethan,西安电子科技大学大三在读,很高兴你能来阅读。
✔️目前博客主要更新Java系列、项目案例、计算机必学四件套等。
🏃人生之义,在于追求,不在成败,勤通大道。加油呀!
🔥个人主页:Ethan Yankang
🔥推荐:史上最强八股文||一分钟看完我的几百篇博客
🔥温馨提示:划到文末发现专栏彩蛋 点击这里直接传送
🔥本篇概览:详细讲解了JVM在调用方法时的方法绑定机制——动态绑定、静态绑定。虚方法、虚方法表。🌈⭕🔥
【计算机领域一切迷惑的源头都是基本概念的模糊,算法除外】
🌈引出:
前一篇章:《剑指JVM》——第4章 动态链接——虚拟机栈6——运行时数据区篇9-CSDN博客
4.7.1 方法调用的分类
前面说了动态链接的作用就是将符号引用转换为调用方法的直接引用。在JVM中,将符号引用转换为调用方法的直接引用与方法的绑定机制相关,方法的绑定机制有两种,分别是态链接和动态链接。
1.静态链接
当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知,且运行期保持不变时。这种情况下,将调用方法的符号引用转换为直接引用的过程称为静态链接。
2.动态链接
如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称为动态链接。
静态链接和动态链接一般还会被称为早期绑定和晚期绑定。意思就是一个字段、方法或者类的符号引用被转换为直接引用的过程,这仅仅发生一次。
代码说明静态动态链接:
class Animal {
public void sound() {
System.out.println("动物发声");
}
}
interface Huntable {
void hunt();
}
class Dog extends Animal implements Huntable {
@Override
public void sound() {
System.out.println("汪汪汪");
}
@Override
public void hunt() {
System.out.println("捕食耗子,多管闲事");
}
}
class Cat extends Animal implements Huntable {
public Cat() {
super(); // 表现为: 静态链接
}
public Cat(String name) {
this(); // 表现为: 静态链接
}
@Override
public void sound() {
super.sound(); // 表现为: 静态链接
System.out.println("喵喵喵");
}
@Override
public void hunt() {
System.out.println("捕食耗子,天经地义");
}
}
class AnimalTest {
public void showAnimal(Animal animal) {
animal.sound(); // 表现为: 动态链接
}
public void showHunt(Huntable h) {
h.hunt(); // 表现为: 动态链接
}
}
上面代码中有类Animal和接口Huntable,Dog类和Cat类继承了Animal类和实现了Huntable接口,并且重写了sound()方法和hunt()方法。
在测试类AnimalTest编写showAnimal(Animal animal)方法,此时是无法在编译期可知的,因为该方法是可以传入Do类和 Cat 类的,无法确定,同理 showHunt(Huntableb)为法也是一样的道理,,本身传入的就接口,更无法确定了,所以这两个方法都是动态链接。Cat类中的构造方法Cat()则可以在编译期确定,因为该方法就是针对Cat类的实例调的,所以是静态链接,Dog 类同理。
随着高级语言的横空出世,类似于Java的面向对象的编程语言越来越多,尽管这类编释语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持装、继承和多态等面向对象特性。既然这一类的编程语言具备多态特性,那么自然也就具备静态链接和动态链接两种绑定方式。
4.7.2虚方法和非虚方法
前面说了方法绑定分为静态链接和动态链接,静态链接是指方法在编译期就确定了具体的调用版本,这个版本在运行时是不可变的,一般称这样的方法为非虚方法。除去非虚方法的都叫作虚方法。
一般来说,静态方法、私有方法、fnal方法、实例构造器、父类方法都是非虚方法。在代码清单4-9中showHunt(Huntable h)和 showAnimal(Animal animal)是虚方法,而Cat类中的构造方法 Cat() 是非虚方法。
4.7.4 方法重写的本质
虚方法的多态性的前提是建立在方法的重写和类的继承的基础上,Java语言中方法重写的本质如下:
(1)找到操作数栈顶的第一个元素所指向的对象的实际类型,记作C。
(2)如果在类型C中找到与常量中的描述符和简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果不通过,则返回iava.lamg1legalAccessError异常。
IlegalAccessError 异常表示程序试图访问或修改一个属性或调用一个方法,但是没有对应的权限。一般来说,IIegalAccessEmor异常会引起编译器异常。这个错误如果发生在运行时,就说明一个类发生了不兼容的改变。例如,Maven的iar包冲突。
(3)如果在类型C中找不到与常量中的描述符和简单名称都相符的方法,按照继承关系从下往上依次对C的各个父类进行第2步的搜索和验证过程。
(4)如果始终没有找到合适的方法,则抛出java.lang.AbstractMethodError 异常。
4.7.5 虚方法表
在面向对象的编程中,会频繁使用动态分派,即在运行期根据实际变量类型确定方法执行版本。方法执行版本的选择需要在类的方法元数据中搜索合适的目标方法,所以频繁地搜索会影响 JVM 的性能。因此JVM 通过在类的方法区建立一个虚方法表(Virtual Method Table)来提高性能,使用虚方法表索引表来代替查找。
每个类中都有一个虚方法表,表中存放着各个方法的实际入口,那么虚方法表什么时候被创建?
虚方法表会在类加载的链接阶段被创建并开始初始化,类的变量初始值准备完成之后,JVM 会把该类的虚方法表也初始化完毕。
如图 4-31 所示,Son 类继承于 Father 类,Father 类包含 talk() 和 eat() 两个方法,Son 类重写了Father 类的 talk() 方法和 eat()方法。当在 Son 类调用 toString()等方法时直接找到 Object类不用再经过 Father 类,虚方法表的作用就是可以直接调用 Obiect 类中的方法,从而提高效率。
💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖💖
热门专栏推荐
🌈🌈计算机科学入门系列 关注走一波💕💕
🌈🌈CSAPP深入理解计算机原理 关注走一波💕💕
🌈🌈微服务项目之黑马头条 关注走一波💕💕
🌈🌈redis深度项目之黑马点评 关注走一波💕💕
🌈🌈JAVA面试八股文系列专栏 关注走一波💕💕
🌈🌈JAVA基础试题集精讲 关注走一波💕💕
🌈🌈代码随想录精讲200题 关注走一波💕💕
总栏
🌈🌈JAVA基础要夯牢 关注走一波💕💕
🌈🌈JAVA后端技术栈 关注走一波💕💕
🌈🌈JAVA面试八股文 关注走一波💕💕
🌈🌈JAVA项目(含源码深度剖析) 关注走一波💕💕
🌈🌈计算机四件套 关注走一波💕💕
🌈🌈数据结构与算法 关注走一波💕💕
🌈🌈必知必会工具集 关注走一波💕💕
🌈🌈书籍网课笔记汇总 关注走一波💕💕
📣非常感谢你阅读到这里,如果这篇文章对你有帮助,希望能留下你的点赞👍 关注❤收藏✅ 评论💬,大佬三连必回哦!thanks!!!
📚愿大家都能学有所得,功不唐捐!