在前面的文章中,有详细地介绍java字节码相关的知识,有兴趣的可以提前了解一下。

1.Java字节码的一段旅行经历——提升硬实力1

2.Java字节码角度分析a++ ——提升硬实力2

3.Java字节码角度分析条件判断指令 ——提升硬实力3

4.Java字节码角度分析循环控制 ——提升硬实力4

5.Java字节码角度分析判断结果 ——提升硬实力5

6.Java字节码角度分析构造方法 ——提升硬实力6

7.Java字节码角度分析方法调用 ——提升硬实力7


通过:7.Java字节码角度分析方法调用 ——提升硬实力7,我们已经知道了如下知识:

  1. invokespecial只能调用三类方法:<init>方法、private方法、super.method()。因为这三类方法的调用对象在编译时就可以确定。
  2. invokevirtual是一种动态分派的调用指令:也就是引用的类型并不能决定方法属于哪个类型。

接下来,我们将以字节码的视角来分析java多态原理,先来看一下java多态实现的示例:

// 从字节码角度来分析:多态原理
/*** 演示多态原理,注意加上下面的 JVM参数,禁用指针压缩* -XX:-UseCompressedOops -XX:-UseCompressedClassPointers*/
public class T12_ByteAnalyseDuoTai {// 此处,就会有多态应用。public static void test(Animal animal) {// 因为animal有可能是狗,也可能是猫,且不同对象eat方法实现不一样// 后续将演示eat方法是哪个对象调用,从字节码角度对eat方法查找调用过程animal.eat();System.out.println(animal.toString());}public static void main(String[] args) throws IOException {test(new Cat());test(new Dog());System.in.read();}
}abstract class Animal {public abstract void eat();@Overridepublic String toString() {return "我是" + this.getClass().getSimpleName();}
}class Dog extends Animal {@Overridepublic void eat() {System.out.println("啃骨头");}
}class Cat extends Animal {@Overridepublic void eat() {System.out.println("吃鱼");}
}

上述代码通过:javap -v T12_ByteAnalyseDuoTai.class进行反编译,得到如下字节码。得到:动态方法在字节码层面是通过invokevirtual 来调用的。

上述代码产生的多态应用,因为Animal具体实例有可能是狗,也可能是猫,且不同对象 eat() 方法实现不一样,接下来将演示 eat() 方法是哪个对象调用,从字节码角度对 eat() 方法查找调用过程

1、运行代码

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

2、运行HSDB工具

  • 进入JDK安装目录,执行:java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB
  • 进入图形界面attach 进程id

3、HSDB - HotSpot Debugger -> Tools -> Find Object by Query

输入查询语句:select d from com.jvm.t07_bytecode.T12_ByteAnalyseDuoTai.Dog d,如下图

点击Dog 对象内存地址,就会得到Dog对象在内存的实际表示,如下图:

接下来,继续通过Dog对象内存地址继续查看Dog对象在内存的表现形式

我们复制0x000000001c794028,继续在【Tools】-> 【Inspector】查看对象在java内存的完整表示,如下:

接下来,继续查找多态方法。多态方法是存在于一张叫vtable虚方法表中,在Dog类对象在java内存的完整表示最后面。找到虚方法表,需要在当前地址 0x000000001c794028 加上 1B8 = 0x000000001c7941E0

接下来通过【Windows】 -> 【console】查找Dog类对应的虚方法表信息,指令如下:其中6是指虚方法表的长度

  • mem 0x000000001c7941E0 6

得到了Dog类对应所有重写方法的入口地址,如下图:

上述说的Dog类所有重写的方法,具体对应哪些方法呢。我们知道Dog类继承自Animal,Animal继承自Object。接下来,分别从Dog、Animal、Object类进行查找。通过【Tools】 -> 【Class Browser】

说明:Dog类vtable虚方法表中调用的 eat() 方法是 Dog 类的 eat() 方法,不是 Cat 类的 eat() 方法,也不是 Animal 类的 eat() 方法。

接下来继续虚方法表vtable其他方法调用的是哪个方法,查找Dog类的父类Animal类, 如下图:

说明:Dog类虚方法表中 toString() 方法调用的是 Animal 的 toString() 方法,因为 Dog 类没有 toString() 方法,因父类 Animal 有 toString() 方法。

最后,再来看一下Object类,如下图:

总结:通过对象找到它的 Class 类,获取到它的虚方法表后,就能确定虚方法表中每个方法实际的方法入口地址。有的来自于自己(eat方法),有的来自于父类(toString方法)。将来,对象调用方法时,就能明确知道调用哪个方法了。最后提醒大家,虚方法表是在类的加载过程的链接阶段生成的,所以在链接阶段就已经确定了虚方法表每个方法的入口地址


小结

一句话总结:invokevirtual 指令调用的对象vtable中的方法。

多态方法调用,当执行 invokevirtual指令时,

  1. 先通过栈帧中的对象引用找到对象
  2. 分析对象头,找到对象的实际Class
  3. Class结构中有vtable,它在类加载的链接阶段就已经根据方法的重写规则生成好了
  4. 查表到得方法的具体地址
  5. 执行方法的字节码

多态方法调用,需要在执行过程中经过虚方法表多次查找,过程比较复杂。如果从细微的效率来说,它是不如static。

当然jvm底层也做很多虚方法表查找过程的优化,比如缓存、经常查找的方法放入缓存,这样查找较快。如果Animal只有Dog继承,没有Cat继承的话,jvm会将多态转换为单态,这样加快方法的寻址速度。


文章最后,给大家推荐一些受欢迎的技术博客链接

  1. Hadoop相关技术博客链接
  2. Spark 核心技术链接
  3. JAVA相关的深度技术博客链接
  4. 超全干货--Flink思维导图,花了3周左右编写、校对
  5. 深入JAVA 的JVM核心原理解决线上各种故障【附案例】
  6. 请谈谈你对volatile的理解?--最近小李子与面试官的一场“硬核较量”
  7. 聊聊RPC通信,经常被问到的一道面试题。源码+笔记,包懂

欢迎扫描下方的二维码或 搜索 公众号“10点进修”,我们会有更多、且及时的资料推送给您,欢迎多多交流!

Java字节码角度分析多态原理 ——提升硬实力8相关推荐

  1. Java字节码角度分析:Synchronized ——提升硬实力11

    在前面的文章中,有详细地介绍java字节码相关的知识,有兴趣的可以提前了解一下. 1.Java字节码的一段旅行经历--提升硬实力1 2.Java字节码角度分析a++ --提升硬实力2 3.Java字节 ...

  2. Java字节码角度分析方法调用 ——提升硬实力7

    在前面的文章中,有详细地介绍java字节码相关的知识,有兴趣的可以提前了解一下. 1.Java字节码的一段旅行经历--提升硬实力1 2.Java字节码角度分析a++ --提升硬实力2 3.Java字节 ...

  3. java异常 字节码,Java字节码角度分析异常处理

    目录 从字节码角度来分析:异常处理 1.1 异常-catch // 从字节码角度来分析:异常处理 public class T13_ByteAnalyseException { public stat ...

  4. 从字节码角度分析Byte类型变量b++和++b

    1. 下面是一到Java笔试题: 1 public class Test2 2 { 3 public void add(Byte b) 4 { 5 b = b++; 6 } 7 public void ...

  5. 【易懂】Java源码角度分析put()与putIfAbsent()的区别——源码分析系列

    一.put()方法 1. 源码分析 Java中并未给出put()的源码,因此我们看一下put()方法中给出的注释: Associates the specified value with the sp ...

  6. java try resource_从 Java 字节码角度看 try with resource 语法糖

    Java 7中的 try-with-resource,在没有这个语法糖的情况下的等价实现是什么? 以下面的demo为例,这个问题目测99%的人都写不完全正确,不信来战. public static v ...

  7. 这一次,彻底弄懂 Java 字节码文件!

    作者 | 东升的思考 责编 | Elle 不啰嗦,直接从最最简单的一段Java源代码开启Java整体字节码分析之旅. Java 源码文件 package com.dskj.jvm.bytecode; ...

  8. 【Java 虚拟机原理】Class 字节码二进制文件分析 七 ( 局部变量表分析 )

    文章目录 前言 一.编译生成带局部变量表的字节码文件 二.局部变量表 前言 上一篇博客 [Java 虚拟机原理]Class 字节码二进制文件分析 二 ( 常量池位置 | 常量池结构 | tag | i ...

  9. 【Java 虚拟机原理】Class 字节码二进制文件分析 六 ( 属性类型 | Code 属性 | 属性名称索引 | 属性长度 | 操作数栈最大深度 | 局部变量存储空间 | 字节码长度 )

    文章目录 前言 一.属性类型 二.Code 属性表数据结构 三.属性名称索引 四.属性长度 五.操作数栈最大深度 六.局部变量存储空间 七.字节码长度 八.存储字节码指令的一系列字节流 前言 上一篇博 ...

最新文章

  1. 【问题收录】Ubuntu14.04连接两个双显示器失败的解决方案
  2. tomcat架构分析(概览)【转】
  3. C指针原理(15)-C指针基础
  4. 安卓10不支持qmc解码_官宣:安卓10已发布!21款手机已适配,小米华为率先支持...
  5. python 企业微信群机器人_企业微信群机器人应用:使用python从网站抓取行业资讯并定时推送...
  6. sas 文件传输 本地 服务器,SLIM SAS SFF-8654服务器转换线让传输更容易!
  7. 关于bootstrap-table服务端分页问题
  8. linux vim打开乱码,linux下解决vim打开文件乱码现象
  9. 十分钟搞定CSS选择器
  10. oracle的查询数据(检索数据)
  11. Coaching 企业教练
  12. 干货来袭!java从入门到精通第五版pdf
  13. 系统分析师成长之路 转
  14. 计算机在档案管理出现的问题,浅议档案管理中存在的问题及解决措施_档案管理员资格证...
  15. Java工程师成神之路(2020最新版)
  16. 新概念乐理教程——五线谱、简谱—起学
  17. 通俗易懂的讲讲什么是中间件?
  18. [转]爱到支离破碎!!!
  19. 对数似然函数值/最大近然估计/log likelihood
  20. 【ALLEGRO】DRC错误代码

热门文章

  1. 汉塞尔曼的奇妙时事通讯:2013年2月4日
  2. (九)unity自带的着色器源码剖析之——————UnityShadowLibrary.cginc文件分析(实时阴影和烘焙阴影、阴影淡化、阴影渗漏处理、PCF阴影过滤解决实时阴影锯齿)
  3. Ubuntu 20.04制作本地源
  4. c语言教学方法措施,C语言教学方法探讨
  5. 广义根轨迹 matlab,根轨迹心得体会
  6. 没有对公账户怎么开通认证微信公众号?
  7. 海德汉 LSV2 协议采集 2
  8. 怎么用计算机打出汉字,Windows XP电脑入门如何使用输入法输入汉字
  9. C语言三位数分别输出个位十位百位
  10. python3 + opencv +pyzbar实时检测二维码 / 定位二维码,并绘制出二维码的框和提取二维码内容