Java 高级:动态绑定实现机制

本贴最后更新于 3121 天前,其中的信息可能已经时移俗易

Java 虚拟机调用一个类方法时,它会基于对象引用的类型(通常在编译时可知)来选择所调用的方法。相反,当虚拟机调用一个实例方法时,它会基于对象实际的类型(只能在运行时得知)来选择所调用的方法,这就是动态绑定,是多态的一种。动态绑定为解决实际的业务问题提供了很大的灵活性,是一种非常优美的机制。

1. Java 对象模型

Java 虚拟机规范并没有规定 Java 对象在堆里是如何表示的。对象的内部表示也影响着整个堆以及垃圾收集器的设计,它由虚拟机的实现者决定。

Java 对象中包含的基本数据由它所属的类及其所有超类声明的实例变量组成。只要有一个对象引用,虚拟机就必须能够快速地定位对象实例的数据。另外,它也必须能通过该对象引用访问相应的类数据(存储于方法区的类型信息),因此在对象中通常会有一个指向方法区的指针。当程序在运行时需要转换某个对象引用为另外一种类型时,虚拟机必须要检查这种转换是否被允许,被转换的对象是否的确是被引用的对象或者它的超类型。当程序在执行 instanceof 操作时,虚拟机也进行了同样的检查。所以虚拟机都需要查看被引用的对象的类数据。

不管虚拟机的实现使用什么样的对象表示法,很可能每个对象都有一个方法表因为方法表加快了调用实例方法时的效率。但是 JAVA 虚拟机规范并未要求必须使用方法表,所以并不是所有实现中都会使用它。

下面是一种 Java 对象的内存模型表示:

方法数据存放在类的方法区中,包含一个方法的具体实现的字节码二进制。方法指针直接指向这个方法在内存中的起始位置,通过方法指针就可以找到这个方法。

2. 动态绑定内部机制

方法表是一个指向方法区中的方法指针的数组。方法表中不包含 static、private 等静态绑定的方法,仅仅包含那些需要动态绑定的实例方法。

在方法表中,来自超类的方法出现在来自子类的方法之前,并且排列方法指针的顺序和方法在 class 文件中出现的顺序相同,这种排列顺序的例外情况是,被子类的方法覆盖的方法出现在超类中该方法第一次出现的地方。

例如有超类 Base 和子类 Derive:

public class Base { public Base() { } public void test() { System.out.println( "int Base" ); } public void print() { } } public class Derive extends Base { public Derive() { } public void test() { System.out.println( "int Derive" ); } public void sayHello() { } public static void main( String[] args ) { Base base = new Derive(); base.test(); } }

上例中的 Base 和 Derive 的方法表如下:

在这个例子里,test()方法在 Base 和 Derive 的方法表中都是同一个位置-位置 1。在 Base 方法表中,test()指针是 Base 的 test()方法内存地址;而在 Derive 方法表中,方法表的位置 1 放置的是 Derive 的 test()方法内存地址。

当 Java 虚拟机执行 base.test()时,通过 base 引用可以找到 base 所指向的实际对象的内存位置,现在虚拟机不知道 base 引用的实际对象是 Base 还是 Derive。但是根据上面的对象内存模型,虚拟机从对象内存中的第一个指针“特殊结构指针”开始,可以找到实际对象的类型数据和 Class 实例,这样虚拟机就可以知道 base 引用的实际对象是 Derive 对象。为了执行 test(),虚拟机需要找到 test()的字节码,方法的字节码存放在方法区中。虚拟机从对象内存中的第一个指针“特殊结构指针”开始,搜寻方法表的位置 1,位置 1 指向的 test()方法是 Derive 类的 test()方法,这就是 JAVA 虚拟机将要执行的 test()的字节码。现在,虚拟机知道了调用的实际对象是 Derive 对象,调用的实际 test()方法是 Derive 类的 test()方法,所以 JAVA 虚拟机能够正确执行-调用 base 引用的实际对象的方法而不是 base 引用本身的方法。

这是动态绑定的一种实现方式,根据不同的 JAVA 虚拟机平台和不同的实际约束,动态绑定可以有不同的内部实现机制。

专栏作者简介

陶邦仁:专注于后端技术研究,前端技术略有涉猎,热衷于构建高性能、高可用网站,对平台服务化、分布式服务、分布式存储等方面的解决方案。目前就职于千丁互联,任技术经理一职,负责社区产品技术研发。曾就职于京东,负责库存组缓存方案技术实现;曾就职于百度糯米,负责 PC 首页、APP 个性化排单服务化解决方案。

  • Java

    Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言,是由 Sun Microsystems 公司于 1995 年 5 月推出的。Java 技术具有卓越的通用性、高效性、平台移植性和安全性。

    3202 引用 • 8217 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 650 关注
  • 外包

    有空闲时间是接外包好呢还是学习好呢?

    26 引用 • 233 回帖
  • 心情

    心是产生任何想法的源泉,心本体会陷入到对自己本体不能理解的状态中,因为心能产生任何想法,不能分出对错,不能分出自己。

    59 引用 • 369 回帖
  • ReactiveX

    ReactiveX 是一个专注于异步编程与控制可观察数据(或者事件)流的 API。它组合了观察者模式,迭代器模式和函数式编程的优秀思想。

    1 引用 • 2 回帖 • 179 关注
  • MySQL

    MySQL 是一个关系型数据库管理系统,由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司。MySQL 是最流行的关系型数据库管理系统之一。

    694 引用 • 537 回帖 • 1 关注
  • 工具

    子曰:“工欲善其事,必先利其器。”

    300 引用 • 768 回帖
  • MyBatis

    MyBatis 本是 Apache 软件基金会 的一个开源项目 iBatis,2010 年这个项目由 Apache 软件基金会迁移到了 google code,并且改名为 MyBatis ,2013 年 11 月再次迁移到了 GitHub。

    173 引用 • 414 回帖 • 364 关注
  • Google

    Google(Google Inc.,NASDAQ:GOOG)是一家美国上市公司(公有股份公司),于 1998 年 9 月 7 日以私有股份公司的形式创立,设计并管理一个互联网搜索引擎。Google 公司的总部称作“Googleplex”,它位于加利福尼亚山景城。Google 目前被公认为是全球规模最大的搜索引擎,它提供了简单易用的免费服务。不作恶(Don't be evil)是谷歌公司的一项非正式的公司口号。

    49 引用 • 192 回帖
  • WordPress

    WordPress 是一个使用 PHP 语言开发的博客平台,用户可以在支持 PHP 和 MySQL 数据库的服务器上架设自己的博客。也可以把 WordPress 当作一个内容管理系统(CMS)来使用。WordPress 是一个免费的开源项目,在 GNU 通用公共许可证(GPLv2)下授权发布。

    46 引用 • 114 回帖 • 165 关注
  • Quicker

    Quicker 您的指尖工具箱!操作更少,收获更多!

    37 引用 • 157 回帖
  • Sphinx

    Sphinx 是一个基于 SQL 的全文检索引擎,可以结合 MySQL、PostgreSQL 做全文搜索,它可以提供比数据库本身更专业的搜索功能,使得应用程序更容易实现专业化的全文检索。

    1 引用 • 225 关注
  • DevOps

    DevOps(Development 和 Operations 的组合词)是一组过程、方法与系统的统称,用于促进开发(应用程序/软件工程)、技术运营和质量保障(QA)部门之间的沟通、协作与整合。

    59 引用 • 25 回帖 • 1 关注
  • C

    C 语言是一门通用计算机编程语言,应用广泛。C 语言的设计目标是提供一种能以简易的方式编译、处理低级存储器、产生少量的机器码以及不需要任何运行环境支持便能运行的编程语言。

    86 引用 • 165 回帖
  • Jenkins

    Jenkins 是一套开源的持续集成工具。它提供了非常丰富的插件,让构建、部署、自动化集成项目变得简单易用。

    54 引用 • 37 回帖 • 1 关注
  • Notion

    Notion - The all-in-one workspace for your notes, tasks, wikis, and databases.

    10 引用 • 77 回帖
  • Lute

    Lute 是一款结构化的 Markdown 引擎,支持 Go 和 JavaScript。

    29 引用 • 202 回帖 • 30 关注
  • 游戏

    沉迷游戏伤身,强撸灰飞烟灭。

    187 引用 • 832 回帖
  • Maven

    Maven 是基于项目对象模型(POM)、通过一小段描述信息来管理项目的构建、报告和文档的软件项目管理工具。

    188 引用 • 319 回帖 • 237 关注
  • 自由行
    1 关注
  • Wide

    Wide 是一款基于 Web 的 Go 语言 IDE。通过浏览器就可以进行 Go 开发,并有代码自动完成、查看表达式、编译反馈、Lint、实时结果输出等功能。

    欢迎访问我们运维的实例: https://wide.b3log.org

    30 引用 • 218 回帖 • 645 关注
  • golang

    Go 语言是 Google 推出的一种全新的编程语言,可以在不损失应用程序性能的情况下降低代码的复杂性。谷歌首席软件工程师罗布派克(Rob Pike)说:我们之所以开发 Go,是因为过去 10 多年间软件开发的难度令人沮丧。Go 是谷歌 2009 发布的第二款编程语言。

    500 引用 • 1396 回帖 • 252 关注
  • Windows

    Microsoft Windows 是美国微软公司研发的一套操作系统,它问世于 1985 年,起初仅仅是 Microsoft-DOS 模拟环境,后续的系统版本由于微软不断的更新升级,不但易用,也慢慢的成为家家户户人们最喜爱的操作系统。

    229 引用 • 476 回帖
  • 锤子科技

    锤子科技(Smartisan)成立于 2012 年 5 月,是一家制造移动互联网终端设备的公司,公司的使命是用完美主义的工匠精神,打造用户体验一流的数码消费类产品(智能手机为主),改善人们的生活质量。

    4 引用 • 31 回帖
  • 新人

    让我们欢迎这对新人。哦,不好意思说错了,让我们欢迎这位新人!
    新手上路,请谨慎驾驶!

    52 引用 • 228 回帖
  • 小说

    小说是以刻画人物形象为中心,通过完整的故事情节和环境描写来反映社会生活的文学体裁。

    32 引用 • 108 回帖
  • Solo

    Solo 是一款小而美的开源博客系统,专为程序员设计。Solo 有着非常活跃的社区,可将文章作为帖子推送到社区,来自社区的回帖将作为博客评论进行联动(具体细节请浏览 B3log 构思 - 分布式社区网络)。

    这是一种全新的网络社区体验,让热爱记录和分享的你不再感到孤单!

    1444 引用 • 10083 回帖 • 507 关注
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 150 回帖 • 4 关注