java虚拟机之方法调用(下)——单分派与多分派

前言

上一篇讲解了静态分派和动态分派,还不清楚的同学可以先看看:
java虚拟机之方法调用(上)——静态分派与动态分派

单分派与多分派

静态分派和动态分派是根据判断方法的执行版本的时期来分的,而单分派与多分派是根据方法的接收者和方法的参数的种数来分的。

我们把方法的接收者和方法的参数统称为宗量

具体来说:

单分派是根据一个宗量对目标方法进行选择。
多分派是根据多于一个宗量对目标进行选择。

感觉还是有点抽象,其实简单的说:

单分派是指调用一个对象的方法仅由对象的类型决定。
多分派是指调用一个对象的方法不仅由对象的类型决定,同时还由其他因素决定,比如方法参数的类型等等。

那到底静态分派和动态分派与单分派和多分派有什么关系呢?

下面我们就来一一分析,先看一段代码:

public class Main {
    
    static class Tencent {
    }

    static class Alibaba {
    }

    static class Father {
    
        public void findJob(Tencent tencent) {

            System.out.println("father work in tencent");
        }

        public void findJob(Alibaba ali) {

            System.out.println("father work in alibaba");
        }
    }

    static class Son extends Father {

        @Override
        public void findJob(Tencent tencent) {
            System.out.println("son work in tencent");
        }

        @Override
        public void findJob(Alibaba ali) {
            System.out.println("son work in alibaba");
        }
        
    }


    public static void main(String[] args) {
        Father father = new Father();
        Father son = new Son();
        
        father.findJob(new Tencent());
        son.findJob(new Alibaba());

    }

}

这个一个栗子里面,没有了上一篇博客里面那么单一,只有一个动态分派或者一个静态分派,这个栗子两者都包括,开发中遇到这样的也更多一点。

对于这一个栗子,我们先从编译期间看起:

先看看编译的结果:

同样的,我们找重点看,这里先看24行,编译的结果是Father.findJob(Tencent),说明编译时这里确定了两个地方:一个是接收者类型Father,还有一个是Father里面重载的版本findJob(Tencent),对于确定重载的版本,其实就是有参数的不同类型掺和进来了。

从此可以看出,其实在编译期间,根据两个宗量来选择了目标方法,所以我们说java的静态分派是多分派类型

也可以说在Father类中,同一个类中重载的方法调用,是有类的声明类型和方法参数类型(宗数大于一)决定的。所以是多分派。

如果上来还是有点迷糊的话,不要紧,先看看下面运行期间的分派过程:

由于刚刚我们看到了编译的结果,在第35行:我们明确了在一个类里面,调用的方法版本是findJob(Alibaba),所以在运行的时候,虚拟机不会再关心选择哪一个方法的问题,因为这个时候参数的静态类型、实际类型都对方法的选择不会产生影响了;它现在要关心的是方法的接收者的实际类型,因为不同的实际类型可能有不同的重写版本,所以现在唯一能影响方法的选择的是方法接收者的实际类型这一个宗量,所以java语言的动态分派是单分派类型。

总结

由于java在编译期间,同一个类中重载的方法调用,是有类的静态类型和方法参数类型(宗量大于一)决定的。

而在运行时,重写方法的调用,是由类的实际类型决定的(宗量为一),这也就有了多态。

其实在JDK7以后,加入了invokedynamic指令,而这个指令又使java对多态语言有了一定的支持。而JDK8又加入了lambda,感觉今后java对动态语言的支持会越来越多,所以对于分派的结论也可能会有一定的改变,因为动态语言在编译期间是不会检测一个变量的类型的,因为动态语言的变量根本没有类型,然而只有变量的值有类型。类似的动态语言有javascript、php、python、ruby等。要是读者有兴趣的话,可以去研究研究。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章