深入理解Java虚拟机之虚拟机字节码执行引擎之方法调用

1. 方法调用

方法调用的任务是确定要调用方法的版本,也就是明确要调用哪个方法。方法调用中的目标方法在Class文件里都是一个常量池中的符号引用。类加载的解析阶段会将一部分符号引用转化为直接引用。这类方法主要包括静态方法和私有方法,因为前者直接与类型关联,后者在外部不可被访问,符合“编译器可知,运行期不可变”的要求。他们都不可能通过继承或别的方式重写其他版本,因此适合类加载阶段解析。
大体上静态方法,私有方法,实例构造器,父类方法以及被final修饰的方法在类加载的适合会直接将符号引用解析为该方法的直接引用,这些方法称为非虚方法。

2. 分派

解析调用一定是静态的过程,而分派调用则可能是静态的也可能是动态的。根据分派依据 的宗量数可分为单分派和多分派,这两类又可构成静态单分派,静态多分派,动态单分派及动态多分派四种。静态分配体现重载的实现过程,动态分派体现重写的实现过程。

2.1 静态分配
Human man = new Man();

"Human " 称为变量的静态类型,"Man"称为变量的实际类型。虚拟机在重载时通过参数的静态类型作为判断依据。

public static void main (String[] args) {
	Human man = new Man();
	Human woman = new Woman();
	StaticDispatch sr = new StaticDispatch();
	sr.sayHello(man);
	sr.sayHello(woman);
}

虽然调用的同一方法sayHello且参数分别为man和woman对象,但是方法重载仅依靠静态类型Human判断,因此调用的是Human类的sayHello方法。静态类型和动态类型在应用中可以发生变化,区别是静态类型的变化仅在使用时发生,变量本身的静态类型不会被改变,即不改变原始类型;而实际类型根据运行情况进行变化。

// 实际类型变化
Human man = new Man();
man = new Woman();
// 静态类型变化
sr.sayHello((Man) man)
sr.sayHello((Woman) man)
// 这里实际上还是根据Human判断,调用Human类的方法
sr.sayHello( man)

所有依赖静态类型来定位方法执行版本的分派称为静态分派。静态分配的典型应用是方法重载。

2.2 动态分配

所有依赖动态类型来定位方法执行版本的分派称为动态分派。动态分配的典型应用是方法重写。

Human man = new Man();
Human woman = new Woman();
man.sayHello();
woman.sayHello();
man = new Woman();
man.sayHello();

虽然静态类型Human相同,但是方法重载只依靠动态类型确定,因此具体方法的执行由动态类型指导。

2.3 单分派与多分派
public class Dispatcher {
    static class QQ {}
    static class _360 {}

    public static class Father {
        public void hardChoice(QQ arg) {
            System.out.println("father choose QQ");
        }

        public void hardChoice(_360 arg) {
            System.out.println("father choose _360");
        }
    }

    public static class Son extends Father {
        @Override
        public void hardChoice(QQ arg) {
            System.out.println("son choose QQ");
        }

        @Override
        public void hardChoice(_360 arg) {
            System.out.println("son choose 360");
        }
    }

    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();
        father.hardChoice(new _360());
        son.hardChoice(new QQ());
    }
}

// 输出:father choose 360
		 son choose qq

编译阶段编译器选择过程也就是静态分配(方法重载)的过程,需要根据静态类型(Father or Son)和方法参数(QQ or 360)定位方法,因此静态分派属于多分派类型
运行阶段虚拟机的选择过程也就是动态分派(方法重写)的过程,只需要根据调用者的实际类型判断,因此动态分派属于单分派类型

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值