一、虚函数的定义
定义:在某基类中声明为 virtual 并在一个或多个派生类中被重新定 义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。----------(百度百科)
举个c++中虚函数的例子:
运行可以得到结果:
FUN in A is called
FUN in B is called
代码小改一下:
同样可以得到运行结果:
FUN in A is called
FUN in B is called
读者可以试试将第6行的关键字virtual去掉试运行下,会发现,运行结果如下:
FUN in A is called
FUN in A is called
通过这个例子,可以看到虚函数的作用------实现多态。指向基类的指针在操作它的多态类对象时,会根据不同的类对象,调用其相应的函数,这个函数就是虚函数。
再来看看java语言,
在上面的代码中,我们同样定义了一个基类指针(在java中应该叫引用)去指向不同的对象,可以发现同样可以实现多态。 也就是说,java的普通成员函数(没有被static、native等关键字修饰)就是虚函数,原因很简单,它本身就实现虚函数实现的功能------多态。
下面,我们从更底层的方面来讲述java中虚函数。
二、java字节码
还是之前的代码,我们用javac编译之后,编译器会生成相应的class字节码文件。通过java自带字节码查看器查看
javap -verbose VirtualTest
上面字节码中,有许多指令,如aload_2、invokespecial、invokevirtual(注:aload指令是用来将数据加载到栈,invokespecial用来调用类的构造函数,invokevirtual用来调用普通函数)。
可以发现,对于A.FUN的调用,java虚拟机所采用的调用方式就是invokevirtual。这些字节码的调用指令,是由《java虚拟机规范》规定的,在制定规范之初,大牛们就直接用invokevirtual来命名调用普通函数的指令。从字节码指令的命名上也可以看出,java中的普通成员函数就是虚函数。
从网上有看到这样一种说法,大家可以作为一个参考。
C++ Java
虚函数 -------- 普通函数纯虚函数 -------- 抽象函数
抽象类 -------- 抽象类
虚基类 -------- 接口
结论:java类中普通成员函数就是虚函数。