java-方法调用

解析调用

解析调用是指对那些“编译器可知,运行期不变”的方法的调用,这些方法在编译期就可以确定,并且在解析阶段转换为直接引用,之后就不会改变了。可以进行解析调用的方法有:构造方法、私有方法、final方法、父类方法,这些方法在运行期都是唯一的,不会改变。

 1 public class TempClazz {
 2   public static void main(String[] args) {
 3     TempClazz tempClazz = new TempClazz();
 4     System.out.println("main");
 5     tempClazz.fun();
 6   }
 7   public void fun() {
 8     A.fun();
 9   }
10 
11   private static class A {
12     static {
13       System.out.println("this is A");
14     }
15     public static void fun() {
16       System.out.println("this is A fun");
17     }
18   }
19 }

-XX:+TraceClassLoading输出
[Loaded com.zyong.TempClazz from file:......]
main
[Loaded com.zyong.TempClazz$A from file:......]
this is A
this is A fun

上面测试中,A.fun()的解析并不发生在TempClazz加载阶段,而发生在A.fun()的调用阶段,解析后,A的常量池中对A.fun()的符号引用就会被转换为直接引用,在之后的运行中就可以直接调用了。

 

分派调用

java是一门单分派语言,分派是一门语言将方法调用连接到方法定义的一种方式。通常由接收者(方法调用者)、方法名(包含类名,比如java.lang.Object.hashCode)、实参等因素就可以确定分派,单分派就是只有一个因素决定的分派,多分派就是有多个因素决定的分派。

分派严格来说是动态的,目的就是在运行过程中找到方法定义,并没有静态分派一说。之所以是单分派,是由于java方法的调用只看调用者的实际类型,而不看实参的实际类型(只关注实参的静态类型,这在编译期就已确定)。如果既关注调用者的实际类型,又关注实参的实际类型就是多份派了。

java的多态就是通过分派,在运行时从多个方法版本中找到匹配的那一个。

解析调用和分派调用是不可能同时存在的,分派需要运行时确定方法版本(invokevirtual首先寻找实际类型,然后在实际类型中找对应的方法签名,最终返回直接引用),而解析在解析之后就不会再变了(解析会直接改变常量池中的符号引用为直接引用,而不像动态解析那样需要运行时去寻找直接引用)。

 

 java对象在内存中的样子

如下图就是java对象中字段的布局

 

子类新增字段也没什么区别

 

对于方法的存储,如果每个对象都存储一份方法代码太低效了,方法逻辑是可以共享的,在每个对象中都会有一个Vtable(虚方法表)的引用,这个引用指向Vtable,Vtable中存储了各个方法的实际入口地址(如何在表中查找呢?)。虚表是分派调用才需要的,解析调用在解析阶段将符号引用替换为直接引用,之后的访问都会直接使用直接引用。

 

基于栈的解释器执行过程

1 public int calc() {
2     int a = 100;
3     int b = 200;
4     int c = 300;
5     return (a+b)*c;
6 }

 解释器中,方法的执行涉及jvm指令、程序计数器、操作栈、局部变量表等。

如下图,程序计数器现在是0,表示执行偏移为0的jvm指令(下一条指令istore_1的偏移为2,可以理解为bipush 100是两条指令,bipush一条,100一条),bipush是将单字节整型常量压入操作栈中,istore_1是将栈顶的整型值出栈并存放在第1个局部变量中(第0个存this),sipush是压入4字节整型,iload_1是将局部变量表中的第1个变量复制到栈顶,iadd是将栈中头两个栈顶元素出栈并做整型加法再将结果入栈,imul是做整型乘法,ireturn是将栈顶的整型值返回。

 

参考:http://www.studytonight.com/java/dynamic-method-dispatch.php

  https://www.programcreek.com/2011/11/what-do-java-objects-look-like-in-memory/

posted @ 2017-09-11 21:46  holoyong  阅读(819)  评论(0编辑  收藏  举报