Java的动态分派和静态分派的实现

2020-03-09 16:01:30王振洲
public static void main(String[] args) {
 Human human = new Human();
 Human man = new Man();
 Human woman = new Woman();
 human.say();
 man.say();
 woman.say();
}

main 方法的执行结果:

human
man
woman

意料之中,所谓的多态就是这样。那多态是如何实现的?

其实多态的实现过程也就是确定被重写的方法版本的过程。main 方法编译之后的字节码:

public static main([Ljava/lang/String;)V
 NEW method_invoke/DynamicDispatch$Human
 DUP
 INVOKESPECIAL method_invoke/DynamicDispatch$Human.<init> ()V
 ASTORE 1
 NEW method_invoke/DynamicDispatch$Man
 DUP
 INVOKESPECIAL method_invoke/DynamicDispatch$Man.<init> ()V
 ASTORE 2
 NEW method_invoke/DynamicDispatch$Woman
 DUP
 INVOKESPECIAL method_invoke/DynamicDispatch$Woman.<init> ()V
 ASTORE 3
 // 下面为多态调用 say
 ALOAD 1
 INVOKEVIRTUAL method_invoke/DynamicDispatch$Human.say ()V
 ALOAD 2
 INVOKEVIRTUAL method_invoke/DynamicDispatch$Human.say ()V
 ALOAD 3
 INVOKEVIRTUAL method_invoke/DynamicDispatch$Human.say ()V
 RETURN

这里通过字节码感觉都会调用Hunman#say方法的,但是运行之后并不是。

当 JVM 执行这两行字节码时:

ALOAD 1 
// 由上面 ASTORE 1 可知, 局部变量表的第一个变量是 Woman 的对象
INVOKEVIRTUAL method_invoke/DynamicDispatch$Human.say ()V
// INVOKEVIRTUAL 指令就会到 Woman 类中去寻找 say 方法

调用 say 方法时,JVM 会先去当前调用的对象的类中查找是否存在和目标方法的描述符、简单名称一样的方法,如果存在则将符号引用替换为找到的方法的直接引用,否则就向父类去查找,向父类的父类去查找..., 直到最后找不到抛出NoSuchMethod异常。

Human 的 say 方法的签名:

public void say();
 descriptor: ()V

Woman 的 say 方法的签名:

public void say();
 descriptor: ()V

可见 Woman 类的 Human 类中的 say 方法的描述符和简单名称是一样的,所以 JVM 会优先匹配 Woman 类中的方法。这也是多态调用的底层逻辑。

 到此这篇关于Java的动态分派和静态分派的实现的文章就介绍到这了,更多相关Java 动态分派和静态分派内容请搜索易采站长站以前的文章或继续浏览下面的相关文章希望大家以后多多支持易采站长站!