• 深入理解JVM虚拟机第二十五篇:详解JVM方法的绑定机制静态绑定和动态绑定,早期绑定晚期绑定,并编写代码从字节码角度证明这件事情


    大神链接:作者有幸结识技术大神孙哥为好友,获益匪浅。现在把孙哥视频分享给大家。

    孙哥链接:孙哥个人主页
    作者简介:一个颜值99分,只比孙哥差一点的程序员
    本专栏简介:话不多说,让我们一起干翻JVM

    本文章简介:话不多说,让我们讲清楚JVM当中与操作数栈相关的动态链接和常量池的作用

    文章目录

    一:方法的调用

    1:概述

    2:静态链接

    3:动态链接

    二:方法的绑定

    1:绑定概念

    2:早期绑定

    3:晚期绑定

    三:晚期绑定示例

    1:编写代码

    2:jclasslib查看内容

    四:早期绑定示例 

    1:编写代码

    2:jclasslib查看内容

    五:总结说明


    一:方法的调用

            我们每天都在写方法的调用,但是我们能搞明白其中的原理和JVM当中的操作步骤么?这就是本文的意义。

    1:概述

            官方说法:

            在JVM中,将符号引用转换为调用方法的直接引用这个操作是跟JVM当中方法的绑定机制息息相关的。

            说人话:

            上边这段话是什么意思?我这里给大家解释一下,我们javap整理完毕字节码文件之后,我们会可以在任意一个方法中查看code下的字节码指令,很多字节码指令的后边都会跟#数字这么一个概念,这个就是符号引用,这个引用指向常量池。

            所谓将符号引用转换为方法的直接引用,就是将这个字节码指令后边的符号引用,转变为真实的方法。

            下列中的#3就是符号引用。

    1. public void methodB();
    2. descriptor: ()V
    3. flags: (0x0001) ACC_PUBLIC
    4. Code:
    5. stack=3, locals=1, args_size=1
    6. 0: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
    7. 3: ldc #6 // String methodB().....
    8. 5: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    9. 8: aload_0
    10. 9: invokevirtual #7 // Method methodA:()V
    11. 12: aload_0
    12. 13: dup
    13. 14: getfield #2 // Field num:I
    14. 17: iconst_1
    15. 18: iadd
    16. 19: putfield #2 // Field num:I
    17. 22: return

            从上述找一个例子的话,就是将偏移地址为9的字节码指令后边的#7这个符号引用用真实的方法字面量代替

    2:静态链接

            官方说法:

            当一个字节码文件被装载进JVM内部时,如果被调用的目标方法在编译期可知且运行期保持不变时。这种情况下将调用方法的符号引用转换为直接引用的过程称之为静态链接。

            说人话:

            静态链接:这种方式在编译阶段就已经把符号引用直接转换为了直接引用。

    3:动态链接

            官方说法:

            如果被调用的方法在编译期无法被确定下来,也就是说,只能够在程序运行期将调用方法的符号引用转换为直接引用,由于这种引用转换过程具备动态性,因此也就被称之为动态链接。

            说人话:

            动态链接:这种方式在运行阶段才能把符号引用直接转换为直接引用。

    二:方法的绑定

    1:绑定概念

            绑定是一个字段、方法或者类在符号引用被替换为直接引用的过程,这仅仅发生一次。这个不论是编译器确定还是运行期确定都只会发生一次,不会修改。

            对应的方法的绑定机制为:早期绑定 (Early Bindng)和晚期绑定(Late Binding)。

    2:早期绑定

            官方说法:

            早期绑定就是指被调用的目标方法如果在编译期可知,且运行期保持不变时即可将这个方法与所属的类型进行绑定,这样一来,由于明确了被调用的目标方法究竟是哪一个,因此也就可以使用静态链接的方式将符号引用转换为直接引用。

            说人话:

            早期绑定是和我们的静态绑定相对应的。

    3:晚期绑定

            官方说法:

            如果被调用的方法在编译期无法被确定下来,只能够在程序运行期根据实际的类型绑定相关的方法,这种绑定方式也就被称之为晚期绑定

            说人话:

            晚期绑定是和我们的动态绑定相对应的。

    三:晚期绑定示例

    1:编写代码

    1. class Animal {
    2. public void eat(){
    3. System.out.println("动物进食");
    4. }
    5. }
    6. interface Huntable{
    7. void hunt();
    8. }
    9. class Dog extends Animal implements Huntable{
    10. @Override
    11. public void eat(){
    12. System.out.println("狗吃骨头");
    13. }
    14. @Override
    15. public void hunt() {
    16. System.out.println("捕食耗子,多管闲事");
    17. }
    18. }
    19. class Cat extends Animal implements Huntable{
    20. @Override
    21. public void eat(){
    22. System.out.println("猫吃鱼");
    23. }
    24. @Override
    25. public void hunt() {
    26. System.out.println("捕食耗子,天经地义");
    27. }
    28. }
    29. public class AnimalTest{
    30. public void showAnimal(Animal animal){
    31. animal.eat();//晚期绑定
    32. }
    33. public void showHunt(Huntable h){
    34. h.hunt();//晚期绑定
    35. }
    36. }

    2:jclasslib查看内容

    四:早期绑定示例 

    1:编写代码

    1. class Animal {
    2. public void eat(){
    3. System.out.println("动物进食");
    4. }
    5. }
    6. interface Huntable{
    7. void hunt();
    8. }
    9. class Dog extends Animal implements Huntable{
    10. @Override
    11. public void eat(){
    12. super.eat();//早期绑定
    13. System.out.println("狗吃骨头");
    14. }
    15. @Override
    16. public void hunt() {
    17. System.out.println("捕食耗子,多管闲事");
    18. }
    19. }
    20. class Cat extends Animal implements Huntable{
    21. public Cat(){
    22. super();//早期绑定
    23. }
    24. public Cat(String name){
    25. this();//早期绑定
    26. }
    27. @Override
    28. public void eat(){
    29. System.out.println("猫吃鱼");
    30. }
    31. @Override
    32. public void hunt() {
    33. System.out.println("捕食耗子,天经地义");
    34. }
    35. }
    36. public class AnimalTest{
    37. public void showAnimal(Animal animal){
    38. animal.eat();//晚期绑定
    39. }
    40. public void showHunt(Huntable h){
    41. h.hunt();//晚期绑定
    42. }
    43. }

    2:jclasslib查看内容

            光标放到cat这个类上查看他的jclasslib

             invokeSpecial是早期绑定字节码指令,invokevirtual是晚期绑定的字节码指令。

    五:总结说明

            随着高级语言的横空出世,类似于Java一样的基于面向对象的编程语言如今越来越多,尽管这类编程语言在语法风格上存在一定的差别,但是它们彼此之间始终保持着一个共性,那就是都支持封装、继承和多态等面向对象特性

            既然这一类的编程语言具备多态特性,那么自然也就具备早期绑定和晚期绑定两种绑定方式。

            Java中任何一个普通的方法其实都具备虚函数的特征,也就是运行期才能确定下来,它们相当于c++语言中的虚函数 (c++中则需要使用关键字virtual来显式定义)。

            如果在Java程序中不希望某个方法拥有虚函数的特征时,则可以使用关键字final来标记这个方法。也就是一个方法不想被晚期绑定,直接把他给final修饰即可。

  • 相关阅读:
    springboot生成二维码的正确姿势-附视频附源码
    ffmpeg安装教程(windows、Linux下python环境)
    python实现pdf双页文档转png图片,png图片裁剪为左右两等分,再合并为新的pdf单页文档
    Java8中判断一个对象不为空存在一个类对象是哪个
    2022-8-6 集合容器
    堆——堆排序、模拟堆
    unreal engine oculus 在vr场景中fade in , fade out
    学习大数据开发培训前景如何
    vue 实现高德坐标转GPS坐标
    Hive DDL常见操作
  • 原文地址:https://blog.csdn.net/Facial_Mask/article/details/134409488