【JVM】字节码技术:手撕 多态执行原理

一、源文件

package org.example.classLoading;

import java.io.IOException;
/**
 * 演示多态原理,注意加上下面的 JVM 参数,禁用指针压缩
 * -XX:-UseCompressedOops -XX:-UseCompressedClassPointers
 */
public class PolymorphicTest {
    public static void test(Animal animal){
        animal.eat();
    }
    public static void main(String[] args) throws IOException {
        test(new Cat());
        test(new Dog());
        System.in.read();
    }
}

abstract class Animal {
    public abstract void eat();

    @Override
    public String toString() {
        return "我是"+this.getClass().getSimpleName();
    }
}
class Dog extends Animal{
    @Override
    public void eat() {
        System.out.println("啃骨头");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("吃鱼");
    }
}

二、运行代码

停在 System.in.read() 方法上,这时运行 jps 获取进程 id:4268

PS F:\software\IDEA\JavaProjects\JvmTest> jps
5956 Launcher
10956
17596 Jps
4268 PolymorphicTest

三、运行HSDB工具

进入 JDK 安装目录,执行

F:\software\Java\jdk1.8.0_333>java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB

进入图形界面 attach 进程 id

在这里插入图片描述

四、查找某个对象

打开 Tools -> Find Object By Query

输入 select d from org.example.classLoading.Dog d 点击 Execute 执行

在这里插入图片描述

五、查看对象内存结构

点击 0x0000020f086acd98 可以看到对象的内存结构。此对象没有任何属性,因此只有对象头的 16 字节

前 8 字节是 MarkWord,后 8 字节就是对象的 Class指针 。目前看不到 Class对象 的实际地址

在这里插入图片描述

六、查看对象Class的内存地址

方式一:连接前面第五节

可以通过 Windows -> Console 进入命令行模式,执行下面命令查找对象中word的内存地址

mem 0x0000020f086acd98 2

命令中有两个参数。参数 1 是对象地址,参数 2 是查看 2 行(即 16 字节)

结果中第二行 0x0000020f373d4128 即为 Class对象 的内存地址

在这里插入图片描述

方式二

Tools -> Class Browser 输入 Dog 查找,可以得到相同的结果:0x0000020f373d4128

在这里插入图片描述

七、查看类的多态方法表

Alt+R 进入 Inspector 工具,输入刚才的 Class对象 内存地址,看到如下界面

在这里插入图片描述

无论通过哪种方法,都可以找到 Dog Class对象 内存地址。发现 vtable 长度为 6,意思就是 Dog 类有 6 个虚方法(多态相关的。final,static 不会列入)

那么这 6 个方法都是谁呢?从 Class 的起始地址开始算,偏移 0x1b8 就是 vtable 的起始地址,进行计算得到:

0x0000020f373d4128
			   1b8 +
--------------------
0x0000020f373d42e0

通过 Windows -> Console 进入命令行模式,执行下面命令。得到了 6 个虚方法的入口地址

mem 0x0000020f373d42e0 6

在这里插入图片描述

八、验证方法地址

通过 Tools -> Class Browser 查看每个类的方法定义,比较可知:

  1. Dog - public void eat() @0x0000020f373d40d0

    在这里插入图片描述

  2. Animal - public java.lang.String toString() @0x0000020f373d36a8

    在这里插入图片描述

  3. Object - protected void finalize() @0x0000020f36fd1b10

  4. Object - public boolean equals(java.lang.Object) @0x0000020f36fd15e8

  5. Object - public native int hashCode() @0x0000020f36fd1540

  6. Object - protected native java.lang.Object clone() @0x0000020f36fd1678

    在这里插入图片描述

九、小结

当执行 invokevirtual 指令时

  1. 先通过栈帧中的对象引用找到对象
  2. 分析对象头,找到对象的 实际Class
  3. Class 结构中有 vtable,它在类加载的链接阶段就已经根据方法的重写规则生成好了
  4. 查vtable表 得到方法的具体地址
  5. 执行方法的字节码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

愿你满腹经纶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值