本文是《深入理解Java虚拟机》8.3.2节的读书笔记,理解有误的地方,欢迎指正

首先是两个概念:

静态类型,即是变量声明时的类型。

实际类型,变量实例化时采用的类型。

比如我们有这样一段代码

class Human {}

public class Man extends Human {

public static void main(String[] args) {

Human man = new Man();

}

}

我们就称变量 man 的静态类型为 Human,实际类型为 Man。

静态分派

所有依赖静态类型来定位方法执行版本的分派动作称为静态分派,其典型应用是方法重载(根据参数的静态类型来定位目标方法)。

静态分派发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机执行的。

动态分派

在运行期根据实际类型确定方法执行版本。

比如这样一段代码,其中man和woman的静态类型都是Human,但是实际类型各异:

public class DynamicDispatch {

public static void main(String[] args) {

Human man = new Man();

Human woman = new Woman();

man.sayHello(); // Output : man say hello

woman.sayHello(); // Output : woman say hello

}

private static abstract class Human {

protected abstract void sayHello();

}

private static class Man extends Human {

protected void sayHello() {

System.out.println("man say hello");

}

}

private static class Woman extends Human {

protected void sayHello() {

System.out.println("woman say hello");

}

}

}

编译过后所得的字节码文件如下:

(常量池的部分内容)

Constant pool:

#1 = Methodref #8.#23 // java/lang/Object."":()V

#2 = Class #24 // DynamicDispatch$Man

#3 = Methodref #2.#25 // DynamicDispatch$Man."":(LDynamicDispatch$1;)V

#4 = Class #26 // DynamicDispatch$Woman

#5 = Methodref #4.#25 // DynamicDispatch$Woman."":(LDynamicDispatch$1;)V

#6 = Methodref #13.#27 // DynamicDispatch$Human.sayHello:()V

public class DynamicDispatch {

public DynamicDispatch();

Code:

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: return

public static void main(java.lang.String[]);

Code:

0: new #2 // class DynamicDispatch$Man

3: dup

4: aconst_null

5: invokespecial #3 // Method DynamicDispatch$Man."":(LDynamicDispatch$1;)V

8: astore_1

9: new #4 // class DynamicDispatch$Woman

12: dup

13: aconst_null

14: invokespecial #5 // Method DynamicDispatch$Woman."":(LDynamicDispatch$1;)V

17: astore_2

18: aload_1 // 将第二个引用类型本地变量(man)推送至操作数栈栈顶

19: invokevirtual #6 // Method DynamicDispatch$Human.sayHello:()V,调用#6代表的实例方法,并且方法的接收者就是操作数栈顶元素

22: aload_2

23: invokevirtual #6 // Method DynamicDispatch$Human.sayHello:()V

26: return

}

在main函数中,0~8是创建Man对象并赋到man,9~17是创建woman对象并赋到woman,18就是将man对象压入操作数栈栈顶,接下来19调用Human的sayHello方法,执行的字节码指令是invokevirtual,其具有多态查找过程,在运行时的解析过程大致为:

找到操作数栈顶的第一个元素所指向的对象的实际类型,记为C。

如果在类型C中找到与常量中的描述符合简单名称都相符的方法,则进行访问权限校验,如果通过则返回这个方法的直接引用,查找过程结束;如果权限校验不通过,返回java.lang.IllegalAccessError异常。

否则,按照继承关系从下往上一次对C的各个父类进行第2步的搜索和验证过程。

如果始终没有找到合适的方法,则抛出 java.lang.AbstractMethodError异常。

这里方法的接收者——即操作数栈栈顶元素是man对象,最后的结果就是调用了Man中的sayHello方法。同样的,对woman对象的方法调用也是如此,最后执行的是Woman中的sayHello方法。

由于invokevirtual指令执行的第一步就是在运行期间确定接收者的实际类型,所以两次调用中的invokevirtual指令把常量池中的类方法符号引用解析到了不同的直接引用上,这个过程就是Java方法重写的本质。

java 静态分派_Java中的静态分派与动态分派相关推荐

  1. java构造块_java中的静态代码块、构造代码块、构造方法详解

    运行下面这段代码,观察其结果: package com.test; public class HelloB extends HelloA { public HelloB() { } { System. ...

  2. java静态代码块和静态变量_Java中的静态变量、静态方法与静态代码块

    我们知道类的生命周期分为装载.连接.初始化.使用和卸载的五个过程. 其中静态代码在类的初始化阶段被初始化.而非静态代码则在类的使用阶段(也就是实例化一个类的时候)才会被初始化. 静态变量 可以将静态变 ...

  3. java静态局部变量_java中成员变量,局部变量,静态变量的辨析

    转自百度:https://baijiahao.baidu.com/s?id=1625360816541592483&wfr=spider&for=pc 1.java中成员变量,局部变量 ...

  4. java静态导入_Java中越来越多地接受静态导入吗?

    java静态导入 曾经有一段时间,至少在礼貌的社会中,人们普遍认为使用" 不是 "一词是不可接受的. 确实,在那个时候(也许直到今天),很多人确实(也确实)不认为这不是一个真实的词 ...

  5. java的静态如何理解_java中的静态是什么?如何理解?

    在Java语言中,static表示"静态"的意思,使用场景可以用来修饰成员变量和成员方法,当然也可以是静态代码块.static的主要作用在于创建独立于具体对象的域变量或者方法. 格 ...

  6. java键盘输入字符串静态变量_Java 中为什么样在静态方法中可以调用的方法、可以使用的成员变量必须是静态的?老师说字符串常量和静态变量放在data segment中...

    在上一篇文章中,小编为您详细介绍了关于<C字符串以'\0'结尾的问题?为什么样C语言字符串常量可以当做指针>相关知识.本篇中小编将再为您讲解标题Java 中为什么样在静态方法中可以调用的方 ...

  7. java 静态线程_Java线程类静态本机void yield()方法(带示例)

    线程类静态本机无效 yield()软件包java.lang.Thread.yield()中提供了此方法. yield()方法表示停止当前正在执行的线程,并为其他优先级相同的等待线程提供机会. 如果没有 ...

  8. java工厂模式静态工厂_Java设计模式之静态工厂模式详解

    本文实例讲述了Java设计模式之静态工厂模式.分享给大家供大家参考,具体如下: 静态工厂模式(static factory)也叫简单工厂模式. 涉及到3个角色:工厂类角色,抽象产品类角色和具体产品类角 ...

  9. java 静态方法覆盖_Java中方法的覆盖和静态方法的隐藏

    下面的程序对巴辛吉小鬣狗和其它狗之间的行为差异进行了建模.如果你不知道 什么是巴辛吉小鬣狗,那么我告诉你,这是一种产自非洲的小型卷尾狗,它们从 来都不叫唤.那么,这个程序将打印出什么呢? class ...

最新文章

  1. 网络中常见的互通与不通—Vecloud微云
  2. 如果你有15M 你会投到那些项目上上面呢?机会-可行性模型帮助你
  3. 台式电脑改ip地址能不能上外网_如何将电脑当做路由器来用?一招让你不用为路由器发愁...
  4. 放置游戏如何成爆款?我们在《最强蜗牛》中找到了答案
  5. 大数据薪资一再飙升 学习大数据需要哪些基础?
  6. JavaScript 匿名函数与闭包
  7. css中字间距调整(转)
  8. 第一百七十四天 how can i 坚持
  9. CUDA 计算pi (π)
  10. asc怎么用 linux zip_linux的asc文件怎么打开
  11. 华为机试HJ84:统计大写字母个数
  12. NOTE_网络存储-3 by 张冬
  13. 计算机sql查询同行并集,SQL查询交集、并集、差集
  14. 在electron应用中检测网络
  15. 3个技巧教你做好微博号运营
  16. 从瑞银集团看客户导向型财富管理机构如何从资产配置服务中获利
  17. 基于 Electron 实现 uTools 的超级面板
  18. 此实现不是 Windows 平台 FIPS 验证的加密算法的一部分解决办法
  19. gstreamer AV sync
  20. 从苏宁电器到卡巴斯基第25篇:难忘的三年硕士时光 III

热门文章

  1. 取消挂载点可以节省磁盘么_磁盘克隆、磁盘镜像还有复制粘贴有什么不一样?...
  2. iis php json文件,配置iis支持.json格式的文件
  3. 【Python教程】七种创建对象的方式,你知道几种?
  4. 如何在Python中表示一个对象
  5. python 关于异常处理 try...except... 的两个案例
  6. java 定时删除_Java编写定时删除文件程序
  7. mysql安装在opt_一、编译安装第一个MySQL 5.1.33cd /opt/usr/sbin/groupadd mysql/usr/sbin/useradd -g...
  8. 中新赛克数据可视化_中新赛克——能否构建更安全的世界
  9. 计算机组成原理 位宽,数据总线宽度一般为存储单元位宽的整数倍 这怎么理解哦...
  10. linux运行脚本报错:/bin/bash^M: bad interpreter: No such file or directory(dos2unix )(/bin/sh^M)(回车符、换行符)