Java 虚拟调用(virtual invoke)分析

来源:互联网 发布:淘宝微信返现是真的吗 编辑:程序博客网 时间:2024/05/16 07:05

此文章来分析下,Java 的虚拟调用。
When we say Java language has virtual method calling we mean that in java applications the executed method is determined by the object type in run time.
Java的虚拟方法调用,指的是,调用的方法是由对象运行时的类型决定的。
那么什么是虚拟方法呢?

虚拟方法

我们看下维基百科的介绍,
In object-oriented programming, a virtual function or virtual method is a function or method whose behavior can be overridden within an inheriting class by a function with the same signature. This concept is an important part of the polymorphism portion of object-oriented programming (OOP).
简单翻译一下,
在面向对象编程时,一个虚拟函数或方法,指的是一个可以被继承类重写的函数或方法。该概念是面向对象编程多态的一个重要方面。
OK,简单来说,虚拟方法,就是可以被子类重写的方法。
让我们先看一个例子,
首先我们定义一个基类,

public class BaseClass {    public void methodA() {    };}

ClassA和ClassB分别是BaseClass的子类,

public class ClassA extends BaseClass{    public void methodA() {        System.out.println("call methodA in ClassA! ");    }}public class ClassB extends BaseClass {    public void methodA() {        System.out.println("call methodA in ClassB!");    }}

然后,我们的测试代码,

    public static void main(String[] args) {        BaseClass a = new ClassA();        a.methodA();        BaseClass b = new ClassB();        b.methodA();    }

在此例子中,methodA被子类继承,则是虚拟方法,让我们运行一下main方法,看下输出结果是啥,

call methodA in ClassA! call methodA in ClassB!

此时,我们再看上面提到的虚拟方法调用的定义,调用的方法是由运行时的对象类型决定的。我们来看这个例子,当我们实例化一个ClassA,并赋给a时,此时a的类型表面上是BaseClass,但是其类型却是ClassA,所以执行a.methodA()时,会调用ClassA的方法。此时,你或许会疑问,a的声明类型是BaseClass,为什么运行时的类型是ClassA呢?这也就是Java多态的表现之一。
注意,上面的基类BaseClass,也可以用接口来实现,结果也是一样的。
让我们再看一个复杂一点的例子,
我们修改BaseClass代码如下,

public class BaseClass {    public void methodA() {        System.out.println("call methodA in BaseClass!");        methodB();    };    public void methodB() {        System.out.println("call methodB in BaseClass!");    };}

定义了两个方法,并且methodA中调用methodB,
ClassA继承BaseClass,并重写methodA和methodB方法

public class ClassA extends BaseClass{    public void methodA() {        super.methodA();        System.out.println("call methodA in ClassA! ");    }    public void methodB() {        System.out.println("call methodB in ClassA! ");    }}

我们测试代码如下,

public class Main {    public static void main(String[] args) {        BaseClass a = new ClassA();        a.methodA();    }}

我们来预测一下,输出结果会是什么。
首先根据上个例子,我们可以知道a.methodA()调用的会是ClassA的methodA方法,然后Class.methodA调用父类的methodA方法,父类的methodA又调用methodB方法,那么预期结果应该是这样的,

call methodA in BaseClass!call methodB in BaseClass! call methodA in ClassA! 

然而,运行结果却是这样的,

call methodA in BaseClass!call methodB in ClassA! call methodA in ClassA! 

运行结果与预期结果唯一的不同,在于父类的methodA方法调用methodB方法,是调用自己的?还是调用子类的呢?根据运行结果,我们知道,父类(BaseClass)的methodA方法此时调用的是子类(ClassA)的methodB方法。
让我们再来分析下,当运行a.method()时,会调用super.methodA(),注意此时调用对象是a,也就是ClassA,super.methodA又调用了methodB,根据虚拟调用,由于调用对象类型是ClassA,于是调用ClassA的methodB方法。

根据上面两个例子,希望读者能理解虚拟调用的思想。OPP是个很深奥的东西,希望大家多多学习。

1 0
原创粉丝点击