JVM——方法调用

13 篇文章 0 订阅

概念

方法调用并不等同于方法执行,方法调用阶段唯一的任务就是确定被调用方法的版本(即调用哪一个方法),暂时还不设计方法内部的具体运行过程。在程序运行时,进行方法调用是最普遍、最频繁的操作,Class文件的编译过程中不包含传统编译中的连接步骤,一切方法调用在Class文件里面存储的都只是符号引用,而不是方法在实际运行时内存布局中的入口地址(相对于之前说的直接引用)。这个特性给Java带来了更强大的动态扩展能力,但也使得Java方法调用过程变得相对复杂起来,需要在类加载期间,甚至到运行期间才能确定目标方法的直接引用。

解析

所有丰富的调用中的目标方法在Class文件里面都是一个常量池的符号引用,在类加载的解析阶段,会将其中的一部分符号引用转化为直接引用,这种解析能成立的前提是:**方法在程序真正运行之前就有一个可确定的调用版本,并且方法的调用版本在运行期间是不可改变的。**换句话说,调用目标在程序代码写好、编译器进行编译时就必须确定下来。这类方法的调用称为解析(Resolution)。

在Java语言中符合“编译期可知,运行期不可变”,这个要求的方法,主要包括静态方法和私有方法量大类,前者与类型直接相关,后者在外部不可被访问,这两种方法各自的特点决定了它们都不可能通过继承或别的方式重写其他版本。

public class StaticResolution {

    public static void sayHello() {
        System.out.println("hello world");
    }

    public static void main(String[] args) {
        StaticResolution.sayHello();
    }
}

在这里插入图片描述

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=1, args_size=1
         0: invokestatic  #5                  // Method sayHello:()V
         3: return
      LineNumberTable:
        line 18: 0
        line 19: 3

解析调用一定是一个静态的过程,在编译期间就完全确定,在类装载的解析阶段就会把涉及到的符号引用全部转变为可确定的直接引用,不会延迟到运行期再去完成。而分派(Dispatch)调用则可能是静态的也可能是动态的,根据分派一句的宗量数可分为单分派和多分派。这两类分派方式的两两组合就构成了静态单分派、静态多分派、动态单分派、动态多分派这四种情况。

分派

Java是一门面向对象的程序语言,因为Java具备面向对象的3个基本特征:继承、封装、多态。分派调用过程将会揭示多态性特征的一些最基本的体验,如“重载”和“重写”在Java虚拟机如何实现的。

静态分派

所以依赖静态类型来定位方法执行版本的分配动作称为静态分派。静态分派的典型应用就是方法的重载。在重载时是通过参数的静态类型而不是实际类型作为判断依据的

在这段代码中,创建的对象如:man和women的静态类型为Human,变量的实际类型为Man和Women。方法的接受者依据确定是对象’sr’

代码:

public class Overload {

    public static void sayHello(Object args) {
        System.out.println("hello Object");
    }

    public static void sayHello(int args) {
        System.out.println("hello int");
    }

    public static void sayHello(long args) {
        System.out.println("hello long");
    }

    public static void sayHello(char args) {
        System.out.println("hello char");
    }

    public static void sayHello(char... args) {
        System.out.println("hello char ...");
    }

    public static void sayHello(Serializable args) {
        System.out.println("hello Serializable");
    }

    public static void main(String[] args) {
        sayHello('a');
    }
}

上面代码输出:
hello char

这很好理解,'a’是一个char类型的数据,自然回去寻找参数类型为char的重载方法,如果这里注释掉sayHello(char args)方法,那么输出:
hello int

这里发生了一次自动类型转换,‘a’除了可以代表一个字符串,还可以代表97。因此参数类型为int的重载也是合适的,继续注释掉int方法后,输出为long:
hello long
这里发生了两次自动类型转换,'a’转型为整数97之后,进一步转型为长整型97L,匹配了参数类型为long的重载

。。。。。。

char——>int——>long——>Serializeable——>Object——>Char…

动态分派

动态分派与多态的另一个重要体现——重写(Override)有着很密切的关联。

public class DynamicDispatch {

    static abstract class Human {
        protected abstract void syaHello();
    }

    static class Man extends Human {
        @Override
        protected void syaHello() {
            System.out.println("man say hello");
        }
    }

    static class Women extends Human {
        @Override
        protected void syaHello() {
            System.out.println("women say hello");
        }
    }

    public static void main(String[] args) {
        Human man = new Man();
        Human women = new Women();
        man.syaHello();
        women.syaHello();
        man = new Women();
        man.syaHello();
    }
}

输出结构

man say hello
women say hello
women say hello
  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: new           #2                  // class com/vma/analysis/DynamicD
ispatch$Man
         3: dup
         4: invokespecial #3                  // Method com/vma/analysis/Dynamic
Dispatch$Man."<init>":()V
         7: astore_1
         8: new           #4                  // class com/vma/analysis/DynamicD
ispatch$Women
        11: dup
        12: invokespecial #5                  // Method com/vma/analysis/Dynamic
Dispatch$Women."<init>":()V
        15: astore_2
        16: aload_1
        17: invokevirtual #6                  // Method com/vma/analysis/Dynamic
Dispatch$Human.syaHello:()V
        20: aload_2
        21: invokevirtual #6                  // Method com/vma/analysis/Dynamic
Dispatch$Human.syaHello:()V
        24: new           #4                  // class com/vma/analysis/DynamicD
ispatch$Women
        27: dup
        28: invokespecial #5                  // Method com/vma/analysis/Dynamic
Dispatch$Women."<init>":()V
        31: astore_1
        32: aload_1
        33: invokevirtual #6                  // Method com/vma/analysis/Dynamic
Dispatch$Human.syaHello:()V
        36: return
      LineNumberTable:
        line 32: 0
        line 33: 8
        line 34: 16
        line 35: 20
        line 36: 24
        line 37: 32
        line 38: 36 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值